home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Languguage OS 2
/
Languguage OS II Version 10-94 (Knowledge Media)(1994).ISO
/
gnu
/
screen32.lha
/
screen-3.2b
/
screen.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-10-22
|
86KB
|
3,967 lines
/* Copyright (c) 1991
* Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
* Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de)
* Copyright (c) 1987 Oliver Laumann
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 1, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program (see the file COPYING); if not, write to the
* Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* Noteworthy contributors to screen's design and implementation:
* Wayne Davison (davison@borland.com)
* Patrick Wolfe (pat@kai.com, kailand!pat)
* Bart Schaefer (schaefer@cse.ogi.edu)
* Nathan Glasser (nathan@brokaw.lcs.mit.edu)
* Larry W. Virden (lwv27%cas.BITNET@CUNYVM.CUNY.Edu)
* Howard Chu (hyc@hanauma.jpl.nasa.gov)
* Tim MacKenzie (tym@dibbler.cs.monash.edu.au)
* Markku Jarvinen (mta@{cc,cs,ee}.tut.fi)
* Marc Boucher (marc@CAM.ORG)
*
****************************************************************
*/
#ifndef lint
static char rcs_id[] = "$Id: screen.c,v 1.2 92/02/03 02:28:05 jnweiger Exp $ FAU";
#endif
#include <sys/param.h>
/* #include <signal.h> */
#include <ctype.h>
#include <pwd.h>
#include <fcntl.h>
#ifdef sgi
# include <sys/sysmacros.h>
#endif /* sgi */
#if !defined(sun) && !defined(B43) && !defined(ISC)
# include <time.h>
#endif
/*
* Gee!! We should reverse that #if!
*/
#if defined(sun) || defined(_AIX) || defined(sysV68) || defined(MIPS) || defined(GOULD_NP1) || defined(B43) || defined(ISC) || defined(apollo) || defined(BSDI) || defined(sgi)
# include <sys/time.h>
#endif
#if defined(M_XENIX) || defined(M_UNIX)
#include <sys/select.h> /* for timeval */
#endif
#include <sys/types.h>
#ifdef ISC
# include <sys/bsdtypes.h>
#endif
#if !defined(sysV68) && !defined(M_XENIX)
# include <sys/wait.h>
#endif
#include <sys/stat.h>
#ifndef sgi
# include <sys/file.h>
#endif /* sgi */
#ifndef sun
# include <sys/ioctl.h>
#endif /* sun */
#include <signal.h>
#if defined(SVR4) && !defined(NSIG)
#define NSIG 32
#endif
#include "config.h"
#ifdef SHADOWPW
# include <shadow.h>
#endif /* SHADOWPW */
#ifdef SVR4
# include <sys/stropts.h>
#endif
#ifdef SYSV
# include <sys/utsname.h>
#endif
#if defined(_SEQUENT_)
/* for the FD.. stuff */
# include <sys/select.h>
#endif
#if defined(sequent) || defined(SVR4)
# include <sys/resource.h>
#endif /* sequent || SVR4 */
#ifdef ISC
# include <sys/tty.h>
# include <sys/sioctl.h>
# include <sys/pty.h>
#endif
#include "screen.h"
#include "patchlevel.h"
#if defined(xelos) || defined(sysV68) || defined(M_XENIX)
struct passwd *getpwuid __P((uid_t));
struct passwd *getpwnam __P((char *));
#endif
#ifdef USEVARARGS
# if defined(__STDC__)
# include <stdarg.h>
# else
# include <varargs.h>
# endif
#endif
#ifdef DEBUG
FILE *dfp;
#endif
#ifdef COPY_PASTE
extern char *copybuffer; /* def in mark.c jw. */
extern copylen;
#endif /* COPY_PASTE */
extern char *blank, *null, Term[], screenterm[], **environ, *Termcap;
int force_vt = 1, assume_LP = 0;
extern int in_ovl;
extern int ovl_blockfore;
extern void (*ovl_process)();
extern int help_page;
extern int screenwidth, screenheight;
extern char display_tty[];
extern int default_width, default_height;
extern int Z0width, Z1width;
extern int ISO2022;
extern int status, HS;
extern char *Z0, *WS, *LastMsg;
extern time_t TimeDisplayed;
int BellDisplayed;
int VBellWait, MsgWait, MsgMinWait;
/* tputs uses that: jw */
extern short ospeed;
extern int flow, default_flow, wrap, visual_bell, default_monitor;
extern int errno;
extern sys_nerr;
extern char *sys_errlist[];
extern char mark_key_tab[];
#if defined(TIOCSWINSZ) || defined(TIOCGWINSZ)
extern struct winsize glwz;
#endif
static char *MakeWinMsg __P((char *, int));
static void MakeNewEnv __P((void));
static int Attach __P((int));
static void Attacher __P((void));
static void SigHandler __P((void));
static sig_t AttacherSigInt __P(SIGPROTOARG);
static sig_t SigChld __P(SIGPROTOARG);
static sig_t SigInt __P(SIGPROTOARG);
static sig_t CoreDump __P((int));
static void DoWait __P((void));
static sig_t Finit __P((int));
static void InitKeytab __P((void));
static void SetForeWindow __P((int));
static int NextWindow __P((void));
static int PreviousWindow __P((void));
static int MoreWindows __P((void));
static void FreeWindow __P((struct win *));
static void execvpe __P((char *, char **, char **));
static void LogToggle __P((void));
static void ShowWindows __P((void));
static void ShowTime __P((void));
static void ShowInfo __P((void));
static int OpenPTY __P((void));
#ifdef PASSWORD
static void trysend __P((int, struct msg *, char *));
#endif
#if defined(SIGWINCH) && defined(TIOCGWINSZ)
static sig_t SigAttWinch __P(SIGPROTOARG);
#endif
static void fgtty __P((void));
static void freetty __P((void));
static void brktty __P((void));
#if defined(LOCK)
static sig_t DoLock __P(SIGPROTOARG);
static void LockTerminal __P((void));
#endif
#ifdef COPY_PASTE
static pastelen;
static char *pastebuffer;
#endif
#ifdef PASSWORD
extern char Password[];
#endif
static struct passwd *ppp;
/* used for opening a new pty-pair: */
static char PtyName[32], TtyName[32];
/* used for the attacher's tty: */
static char *attach_tty;
char *ShellProg;
char *ShellArgs[2];
static char inbuf[MAXWIN][IOSIZE];
static inlen[MAXWIN];
static inbuf_ct;
static ESCseen;
static GotSignal;
static char DefaultShell[] = "/bin/sh";
static char DefaultPath[] = ":/usr/ucb:/bin:/usr/bin";
#ifdef hpux
char PtyProto[] = "/dev/ptym/ptyXY";
char TtyProto[] = "/dev/pty/ttyXY";
#else
# if !(defined(sequent) || defined(_SEQUENT_) || defined(SVR4))
static char PtyProto[] = "/dev/ptyXY";
static char TtyProto[] = "/dev/ttyXY";
# endif
#endif /* hpux */
int TtyMode = 0622;
#ifdef SOCKDIR
char *SockDir = SOCKDIR;
#else
char *SockDir = ".iscreen";
#endif
extern char SockPath[], *SockNamePtr, *SockName;
int ServerSocket = -1;
static char **NewEnv;
char *RcFileName = NULL;
char Esc = Ctrl('a');
char MetaEsc = 'a';
char *home;
int HasWindow;
char *LoginName;
char *BellString;
char *VisualBellString;
char *ActivityString;
char *BufferFile;
char *PowDetachString;
int auto_detach = 1;
int iflag, rflag, dflag, lsflag, quietflag, wipeflag;
int adaptflag, loginflag = -1, allflag;
static intrc, startc, stopc;
char HostName[MAXSTR];
int Detached, Suspended;
int DeadlyMsg = 1;
int AttacherPid; /* Non-Zero in child if we have an attacher */
int MasterPid;
int real_uid, real_gid, eff_uid, eff_gid;
int default_histheight;
int default_startup;
int slowpaste;
#if defined(BSDJOBS) && !(defined(POSIX) || defined(SYSV))
int DevTty = -1;
#endif
#ifdef NETHACK
int nethackflag = 0;
#endif
struct mode OldMode, NewMode;
struct win *fore = NULL;
int WinList = -1;
int ForeNum;
struct win *wtab[MAXWIN];
struct key ktab[256];
#ifndef FD_SET
typedef struct fd_set
{
int fd_bits[1];
} fd_set;
# define FD_ZERO(fd) ((fd)->fd_bits[0] = 0)
# define FD_SET(b, fd) ((fd)->fd_bits[0] |= 1 << (b))
# define FD_ISSET(b, fd) ((fd)->fd_bits[0] & 1 << (b))
# define FD_SETSIZE 32
#endif
#ifndef WTERMSIG
# ifndef BSDWAIT /* if wait is NOT a union: */
# define WTERMSIG(status) (status & 0177)
# else
# define WTERMSIG(status) status.w_T.w_Termsig
# endif
#endif
#ifndef WIFCORESIG
# ifndef BSDWAIT /* if wait is NOT a union: */
# define WIFCORESIG(status) (status & 0200)
# else
# define WIFCORESIG(status) status.w_T.w_Coredump
# endif
#endif
#ifndef WEXITSTATUS
# ifndef BSDWAIT /* if wait is NOT a union: */
# define WEXITSTATUS(status) ((status >> 8) & 0377)
# else
# define WEXITSTATUS(status) status.w_T.w_Retcode
# endif
#endif
char *shellaka = NULL;
/*
* Do this last
*/
#include "extern.h"
/*
* XXX: Missing system header files.
*/
#ifdef USEVARARGS
# ifndef VPRNT_DECLARED
int vsprintf __P((char *, char *, va_list));
# endif /* VPRNT_DECLARED */
#endif
int select __P((int, fd_set *, fd_set *, fd_set *, struct timeval *));
static void
brktty()
{
#ifdef POSIX
setsid(); /* will break terminal affiliation */
# ifdef BSD
ioctl(0, TIOCSCTTY, 0);
# endif /* BSD */
#else
# ifdef SYSV
setpgrp(); /* will break terminal affiliation */
# else
# ifdef BSDJOBS
if (DevTty)
if (ioctl(DevTty, TIOCNOTTY, (char *) 0) != 0)
debug2("brktty: ioctl(DevTty=%d, TIOCNOTTY, 0) = %d\n", DevTty, errno);
# endif
# endif
#endif
}
static void
freetty()
{
brktty();
#if defined(BSDJOBS) && !(defined(POSIX) || defined(SYSV))
if (DevTty >= 0)
{
close(DevTty);
DevTty = -1;
}
#endif
close(0);
close(1);
close(2);
debug("did freetty\n");
}
static void
fgtty()
{
#ifdef BSDJOBS
int mypid;
mypid = getpid();
# ifdef BSDI
setsid();
ioctl(0, TIOCSCTTY, 0);
# endif /* BSDI */
# ifdef POSIX
if (tcsetpgrp(0, mypid))
{
debug1("fgtty: tcsetpgrp: %d\n", errno);
/* error is likely to have side-effects -- better to warn our user */
SendErrorMsg("fgtty: Could not set process group id in tty");
}
# else
if (ioctl(0, TIOCSPGRP, &mypid) != 0)
debug1("fgtty: TIOSETPGRP: %d\n", errno);
/* posix setsid() in brktty() from freetty() already made us leader */
if (setpgrp(0, mypid))
debug1("fgtty: setpgrp: %d\n", errno);
# endif /* POSIX */
#endif /* BSDJOBS */
}
#ifdef hpux
/*
* hpux has berkeley signal semantics if we use sigvector,
* but not, if we use signal, so we define our own signal() routine.
* (jw)
*/
void (*signal(sig, func)) ()
int sig;
void (*func) ();
{
struct sigvec osv, sv;
sv.sv_handler = func;
sv.sv_mask = sigmask(sig);
sv.sv_flags = SV_BSDSIG;
if (sigvector(sig, &sv, &osv) < 0)
return (BADSIG);
return (osv.sv_handler);
}
#endif /* hpux */
#ifndef USEBCOPY
#ifdef bcopy
#undef bcopy
#endif
void bcopy(s1, s2, len)
register char *s1, *s2;
register int len;
{
if (s1 < s2 && s2 < s1 + len)
{
s1 += len;
s2 += len;
while (len-- > 0)
*--s2 = *--s1;
}
else
while (len-- > 0)
*s2++ = *s1++;
}
#endif /* USEBCOPY */
void bclear(p, n)
int n;
char *p;
{
bcopy(blank, p, n);
}
static void
closeallfiles()
{
int f;
#ifdef SVR4
struct rlimit rl;
if ((getrlimit(RLIMIT_NOFILE, &rl) == 0) && rl.rlim_max != RLIM_INFINITY)
f = rl.rlim_max;
else
#endif /* SVR4 */
#if defined(SYSV) && !defined(ISC)
f = NOFILE;
#else /* SYSV && !ISC */
f = getdtablesize();
#endif /* SYSV && !ISC */
while (--f > 2)
close(f);
}
static int InterruptPlease = 0;
void main(ac, av)
int ac;
char **av;
{
register int n, len;
register struct win *p;
char *ap, *aka = NULL;
char *av0;
char socknamebuf[2 * MAXSTR];
int s = 0;
fd_set r, w, e;
int mflag = 0;
struct timeval tv;
int nsel;
char buf[IOSIZE], *bufp, *myname = (ac == 0) ? "screen" : av[0];
struct stat st;
int buflen, tmp;
#ifdef _MODE_T /* (jw) */
mode_t oumask;
#else
int oumask;
#endif
#ifdef SYSV
struct utsname utsnam;
#endif
/*
* First, close all unused descriptors
* (otherwise, we might have problems with the select() call)
*/
closeallfiles();
#ifdef DEBUG
(void) mkdir("/tmp/debug", 0777);
if ((dfp = fopen("/tmp/debug/screen.front", "w")) == NULL)
dfp = stderr;
else
(void) chmod("/tmp/debug/screen.front", 0666);
#endif
debug1("-- screen debug started %s\n", *av);
#ifdef POSIX
debug("POSIX\n");
#endif
#ifdef TERMIO
debug("TERMIO\n");
#endif
#ifdef SYSV
debug("SYSV\n");
#endif
#ifdef NAMEDPIPE
debug("NAMEDPIPE\n");
#endif
#if defined(SIGWINCH) && defined(TIOCGWINSZ)
debug("Window changing enabled\n");
#endif
#ifdef NOREUID
debug("NOREUID\n");
#endif
#ifdef hpux
debug("hpux\n");
#endif
#ifdef USEBCOPY
debug("USEBCOPY\n");
#endif
#ifdef UTMPOK
debug("UTMPOK\n");
#endif
#ifdef NETHACK
debug("NETHACK\n");
#endif
#ifdef TERMINFO
debug("TERMINFO\n");
#endif
#ifdef NAME_MAX
debug1("NAME_MAX = %d\n", NAME_MAX);
#endif
BellString = SaveStr("Bell in window %");
VisualBellString = SaveStr(" Wuff, Wuff!! ");
ActivityString = SaveStr("Activity in window %");
BufferFile = SaveStr("/tmp/screen-exchange");
PowDetachString = 0;
default_histheight = DEFAULTHISTHEIGHT;
default_startup = (ac > 1) ? 0 : 1;
adaptflag = 0;
slowpaste = 0;
VBellWait = VBELLWAIT;
MsgWait = MSGWAIT;
MsgMinWait = MSGMINWAIT;
CompileKeys((char *)NULL, mark_key_tab);
av0 = *av;
while (ac > 0)
{
ap = *++av;
if (--ac > 0 && *ap == '-')
{
switch (ap[1])
{
case 'a':
allflag = 1;
break;
case 'A':
adaptflag = 1;
break;
case 'c':
if (ap[2])
RcFileName = ap + 2;
else
{
if (--ac == 0)
exit_with_usage(myname);
RcFileName = *++av;
}
break;
case 'e':
if (ap[2])
ap += 2;
else
{
if (--ac == 0)
exit_with_usage(myname);
ap = *++av;
}
if (!ParseEscape(ap))
Msg(0, "Two characters are required with -e option.");
break;
case 'f':
switch (ap[2])
{
case 'n':
case '0':
default_flow = FLOW_NOW * 0;
break;
case 'y':
case '1':
case '\0':
default_flow = FLOW_NOW * 1;
break;
case 'a':
default_flow = FLOW_AUTOFLAG;
break;
default:
exit_with_usage(myname);
}
break;
case 'h':
if (ap[2])
default_histheight = atoi(ap + 2);
else
{
if (--ac == 0)
exit_with_usage(myname);
default_histheight = atoi(*++av);
}
if (default_histheight < 0)
default_histheight = 0;
break;
case 'i':
iflag = 1;
break;
case 't': /* title is a synonym for AkA */
case 'k':
if (ap[2])
aka = ap + 2;
else
{
if (--ac == 0)
exit_with_usage(myname);
aka = *++av;
}
break;
case 'l':
switch (ap[2])
{
case 'n':
case '0':
loginflag = 0;
break;
case 'y':
case '1':
case '\0':
loginflag = 1;
break;
case 's':
case 'i':
lsflag = 1;
break;
default:
exit_with_usage(myname);
}
break;
case 'w':
lsflag = 1;
wipeflag = 1;
break;
case 'L':
assume_LP = 1;
break;
case 'm':
mflag = 1;
break;
case 'O':
force_vt = 0;
break;
case 'T':
if (ap[2])
{
if (strlen(ap+2) < 20)
strcpy(screenterm, ap + 2);
}
else
{
if (--ac == 0)
exit_with_usage(myname);
if (strlen(*++av) < 20)
strcpy(screenterm, *av);
}
break;
case 'q':
quietflag = 1;
break;
case 'r':
case 'R':
if (ap[2])
{
SockName = ap + 2;
if (ac != 1)
exit_with_usage(myname);
}
else if (ac > 1 && *av[1] != '-')
{
SockName = *++av;
ac--;
}
rflag = (ap[1] == 'r') ? 1 : 2;
break;
#ifdef REMOTE_DETACH
case 'd':
dflag = 1;
/* FALLTHRU */
case 'D':
if (!dflag)
dflag = 2;
if (ap[2])
SockName = ap + 2;
if (ac == 2)
{
if (*av[1] != '-')
{
SockName = *++av;
ac--;
}
}
break;
#endif
case 's':
if (ap[2])
ShellProg = ap + 2;
else
{
if (--ac == 0)
exit_with_usage(myname);
ShellProg = *++av;
}
break;
default:
exit_with_usage(myname);
}
}
else
break;
}
real_uid = getuid();
real_gid = getgid();
eff_uid = geteuid();
eff_gid = getegid();
if (eff_uid != real_uid)
{
/* if running with s-bit, we must install a special signal
* handler routine that resets the s-bit, so that we get a
* core file anyway.
*/
signal(SIGBUS, CoreDump);
signal(SIGSEGV, CoreDump);
}
if (!ShellProg && (ShellProg = getenv("SHELL")) == 0)
ShellProg = DefaultShell;
ShellArgs[0] = ShellProg;
#ifdef NETHACK
nethackflag = (getenv("NETHACKOPTIONS") != NULL);
#endif
home = getenv("HOME"); /* may or may not return a result. jw. */
if ((LoginName = getlogin()) && LoginName[0] != '\0')
{
if ((ppp = getpwnam(LoginName)) != (struct passwd *) 0)
if (ppp->pw_uid != real_uid)
ppp = (struct passwd *) 0;
}
if (ppp == 0)
{
if ((ppp = getpwuid(real_uid)) == 0)
{
#ifdef NETHACK
if (nethackflag)
Msg(0, "An alarm sounds through the dungeon...\nWarning, the kops are coming.");
else
#endif
Msg(0, "getpwuid() can't identify your account!");
exit(1);
}
LoginName = ppp->pw_name;
}
if (home == 0 || *home == '\0')
home = ppp->pw_dir;
if (strlen(LoginName) > 20)
Msg(0, "LoginName too long - sorry.");
if (strlen(home) > MAXPATH - 25)
Msg(0, "$HOME too long - sorry.");
#ifdef PASSWORD
strcpy(Password, ppp->pw_passwd);
#endif
/* ttyname implies isatty */
if (!(attach_tty = ttyname(0)))
{
#ifdef NETHACK
if (nethackflag)
Msg(0, "You must play from a terminal.");
else
#endif
Msg(0, "Must be connected to a terminal.");
exit(1);
}
if (strlen(attach_tty) >= MAXPATH)
Msg(0, "TtyName too long - sorry.");
if ((n = secopen(attach_tty, O_RDWR, 0)) < 0)
Msg(0, "Cannot open '%s' - please check.", attach_tty);
close(n);
debug1("attach_tty is %s\n", attach_tty);
#ifdef _MODE_T
oumask = umask(0); /* well, unsigned never fails? jw. */
#else
if ((oumask = umask(0)) == -1)
Msg(errno, "Cannot change umask to zero");
#endif
if ((SockDir = getenv("ISCREENDIR")) == NULL)
SockDir = getenv("SCREENDIR");
if (SockDir && strlen(SockDir) >= MAXPATH - 1)
Msg(0, "ridiculous long $(I)SCREENDIR - try again.");
#ifndef SOCKDIR
if (SockDir == 0)
{
sprintf(SockPath, "%s/.iscreen", home);
SockDir = SockPath;
}
#endif
if (SockDir)
{
if (access(SockDir, F_OK))
{
if (UserContext() > 0)
{
if (mkdir(SockDir, 0700))
UserReturn(0);
UserReturn(1);
}
if (UserStatus() <= 0)
Msg(0, "Cannot make directory '%s'", SockDir);
}
if (SockDir != SockPath)
strcpy(SockPath, SockDir);
}
#ifdef SOCKDIR
else
{
SockDir = SOCKDIR;
if (stat(SockDir, &st))
{
if (mkdir(SockDir, eff_uid ? 0777 : 0755) == -1)
Msg(errno, "Cannot make directory '%s'", SockDir);
}
else
{
n = eff_uid ? 0777 : 0755;
if ((st.st_mode & 0777) != n)
Msg(0, "Directory '%s' must have mode %03o.", SockDir, n);
}
sprintf(SockPath, "%s/S-%s", SockDir, LoginName);
if (access(SockPath, F_OK))
{
if (mkdir(SockPath, 0700) == -1)
Msg(errno, "Cannot make directory '%s'", SockPath);
(void) chown(SockPath, real_uid, real_gid);
}
}
#endif
if (stat(SockPath, &st) == -1)
{
Msg(errno, "Cannot access %s", SockPath);
}
else
{
#ifdef _POSIX_SOURCE
if (S_ISDIR(st.st_mode) == 0)
#else
if ((st.st_mode & S_IFMT) != S_IFDIR)
#endif
Msg(0, "%s is not a directory.", SockPath);
if (st.st_uid != real_uid)
Msg(0, "You are not the owner of %s.", SockPath);
if ((st.st_mode & 0777) != 0700)
Msg(0, "Directory %s must have mode 700.", SockPath);
}
strcat(SockPath, "/");
SockNamePtr = SockPath + strlen(SockPath);
(void) umask(oumask);
#if defined(SYSV) && !defined(ISC)
if (uname(&utsnam) == -1)
Msg(0, "uname() failed, errno = %d", errno);
else
{
strncpy(HostName, utsnam.nodename, MAXSTR);
HostName[(sizeof(utsnam.nodename) <= MAXSTR) ?
sizeof(utsnam.nodename) : MAXSTR] = '\0';
}
#else
(void) gethostname(HostName, MAXSTR);
#endif
HostName[MAXSTR - 1] = '\0';
if ((ap = index(HostName, '.')) != NULL)
*ap = '\0';
GetTTY(0, &OldMode);
#ifdef POSIX
ospeed = (short) cfgetospeed(&OldMode.tio);
#else
# ifndef TERMIO
ospeed = (short) OldMode.m_ttyb.sg_ospeed;
# endif
#endif
debug1("...setting extern short ospeed = %d\n", ospeed);
if (lsflag)
{
int i;
i = FindSocket(0, (int *)NULL);
/* MakeClientSocket appended the last (Sock)Name there: */
*SockNamePtr = '\0';
if (i == 0)
{
#ifdef NETHACK
if (nethackflag)
Msg(0, "This room is empty (%s)\n", SockPath);
else
#endif /* NETHACK */
Msg(0, "No Sockets found in %s\n", SockPath);
}
else
Msg(0, "%d Socket%s in %s.\n", i, i > 1 ? "s" : "", SockPath);
/* NOTREACHED */
}
if (rflag)
{
debug("screen -r: - is there anybody out there?\n");
#ifdef SHADOWPW
setspent(); /* open shadow file while we are still root */
#endif /* SHADOWPW */
if (Attach(MSG_ATTACH))
{
Attacher();
/* NOTREACHED */
}
debug("screen -r: backend not responding -- still crying\n");
}
else if (dflag)
{
(void) Attach(MSG_DETACH);
DeadlyMsg = 0;
Msg(0, "[%s %sdetached.]\n", SockName, (dflag > 1 ? "power " : ""));
eexit(0);
/* NOTREACHED */
}
if (!mflag && (SockName = getenv("STY")) != 0 && *SockName != '\0')
{
setuid(real_uid);
setgid(real_gid);
s = MakeClientSocket(1, SockName);
if (ac == 0)
{
ac = 1;
av = ShellArgs;
}
av[ac] = aka;
SendCreateMsg(s, ac, av, allflag, default_flow, loginflag, default_histheight,
screenterm);
close(s);
exit(0);
}
#if defined(BSDJOBS) && !(defined(POSIX) || defined(SYSV))
if ((DevTty = open("/dev/tty", O_RDWR | O_NDELAY)) == -1)
Msg(errno, "/dev/tty");
#endif
switch (MasterPid = fork())
{
case -1:
Msg(errno, "fork");
/* NOTREACHED */
case 0:
break;
default:
sprintf(socknamebuf, "%d.%s.%s", MasterPid, stripdev(attach_tty),
HostName);
for (ap = socknamebuf; *ap; ap++)
if (*ap == '/')
*ap = '-';
SockName = socknamebuf;
#ifdef SHADOWPW
setspent(); /* open shadow file while we are still root */
#endif /* SHADOWPW */
Attacher();
/* NOTREACHED */
}
#ifdef DEBUG
if (dfp != stderr)
fclose(dfp);
if ((dfp = fopen("/tmp/debug/screen.back", "w")) == NULL)
dfp = stderr;
else
(void) chmod("/tmp/debug/screen.back", 0666);
#endif
debug("-- screen.back debug started\n");
ap = av0 + strlen(av0) - 1;
while (ap >= av0)
{
if (!strncmp("screen", ap, 6))
{
strncpy(ap, "SCREEN", 6); /* name this process "SCREEN-BACKEND" */
break;
}
ap--;
}
if (ap < av0)
*av0 = 'S';
AttacherPid = getppid();
sprintf(socknamebuf, "%d.%s.%s", getpid(), stripdev(attach_tty), HostName);
for (ap = socknamebuf; *ap; ap++)
if (*ap == '/')
*ap = '-';
SockName = socknamebuf;
ServerSocket = s = MakeServerSocket();
#ifdef ETCSCREENRC
if ((ap = getenv("SYSSCREENRC")) == NULL)
StartRc(ETCSCREENRC);
else
StartRc(ap);
#endif
StartRc(RcFileName);
InitTermcap();
InitTerm(0);
MakeNewEnv();
strcpy(display_tty, attach_tty);
#ifdef UTMPOK
# ifdef apollo
ReInitUtmp();
# else
InitUtmp();
# endif /* apollo */
#endif /* UTMPOK */
signal(SIGHUP, SigHup);
signal(SIGINT, Finit);
signal(SIGQUIT, Finit);
signal(SIGTERM, Finit);
#ifdef BSDJOBS
signal(SIGTTIN, SIG_IGN);
signal(SIGTTOU, SIG_IGN);
#endif
InitKeytab();
#ifdef ETCSCREENRC
if ((ap = getenv("SYSSCREENRC")) == NULL)
FinishRc(ETCSCREENRC);
else
FinishRc(ap);
#endif
FinishRc(RcFileName);
/* Note: SetMode must be called _after_ FinishRc (flow is set there).
*/
SetMode(&OldMode, &NewMode);
SetTTY(0, &NewMode);
if (loginflag == -1)
loginflag = LOGINDEFAULT;
if (ac == 0)
{
ac = 1;
av = ShellArgs;
if (!aka)
aka = shellaka;
}
if (!HasWindow)
{
debug("We open one default window, as screenrc did not specify one.\n");
if (MakeWindow(aka, av, allflag, default_flow, 0, (char *)0, loginflag, -1, (char *)0) == -1)
{
Finit(1);
/* NOTREACHED */
}
}
if (default_startup)
display_copyright();
#ifdef SYSV
signal(SIGCLD, SigChld);
#else
signal(SIGCHLD, SigChld);
#endif
signal(SIGINT, SigInt);
tv.tv_usec = 0;
if (rflag == 2)
{
#ifdef NETHACK
if (nethackflag)
Msg(0, "I can't seem to find a... Hey, wait a minute! Here comes a screen now.");
else
#endif
Msg(0, "New screen...");
rflag = 0;
}
brktty();
for (;;)
{
/*
* check to see if message line should be removed
*/
if (status)
{
int time_left;
debug("checking status...\n");
time_left = TimeDisplayed + (BellDisplayed ? VBellWait : MsgWait) - time((time_t *)0);
if (time_left > 0)
{
tv.tv_sec = time_left;
debug(" not yet.\n");
}
else
{
debug(" removing now.\n");
RemoveStatus();
}
}
/*
* check for I/O on all available I/O descriptors
*/
FD_ZERO(&r);
FD_ZERO(&w);
FD_ZERO(&e);
if (inbuf_ct > 0)
for (n = 0; n < MAXWIN; n++)
#ifdef COPY_PASTE /* wrong here? jw. */
if (inlen[n] > 0 || (pastelen > 0 && n == ForeNum))
#else
if (inlen[n] > 0)
#endif
FD_SET(wtab[n]->ptyfd, &w);
if (!Detached)
FD_SET(0, &r);
for (n = WinList; n != -1; n = p->WinLink)
{
p = wtab[n];
if (p->active && status && !BellDisplayed && !HS)
continue;
if (p->outlen > 0)
continue;
if (in_ovl && ovl_blockfore && n == ForeNum)
continue;
FD_SET(p->ptyfd, &r);
}
FD_SET(s, &r);
(void) fflush(stdout);
if (GotSignal && !status)
{
SigHandler();
continue;
}
if ((nsel = select(FD_SETSIZE, &r, &w, &e, (status) ? &tv : (struct timeval *) 0)) < 0)
{
debug1("Bad select - errno %d\n", errno);
if (errno != EINTR)
{
perror("select");
Finit(1);
}
else
{
errno = 0;
if ((!GotSignal || status) && !InterruptPlease)
continue;
}
}
if (InterruptPlease)
{
char buf[1];
debug("Backend received interrupt\n");
*buf = intrc;
write(wtab[ForeNum]->ptyfd, buf, 1);
debug1("Backend wrote interrupt to %d\n", ForeNum);
InterruptPlease = 0;
continue;
}
if (GotSignal && !status)
{
SigHandler();
continue;
}
/* Process a client connect attempt and message */
if (nsel && FD_ISSET(s, &r))
{
nsel--;
if (!HS)
RemoveStatus();
if (in_ovl)
{
SetOvlCurr();
(*ovl_process)(0, 0); /* We have to abort first!! */
CheckScreenSize(1); /* Change fore */
DeadlyMsg = 0;
#ifdef NETHACK
if (nethackflag)
Msg(0, "KAABLAMM!!! You triggered a land mine!");
else
#endif
Msg(0, "Aborted because of window change or message.");
}
else
CheckScreenSize(1); /* Change fore */
ReceiveMsg(s);
continue;
}
/*
* Write the stored user input to the window descriptors first.
* We do not want to choke, if he types fast.
*/
if (nsel && inbuf_ct > 0)
{
for (n = 0; n < MAXWIN ; n++)
{
if (inlen[n] <= 0)
continue;
tmp = wtab[n]->ptyfd;
if (FD_ISSET(tmp, &w))
{
if ((len = write(tmp, inbuf[n], inlen[n])) > 0)
{
if ((inlen[n] -= len) == 0)
inbuf_ct--;
bcopy(inbuf[n] + len, inbuf[n], inlen[n]);
}
if (--nsel == 0)
break;
}
}
}
/* Read, process, and store the user input */
if (nsel && FD_ISSET(0, &r))
{
nsel--;
if (!HS)
RemoveStatus();
if (ESCseen)
{
buf[0] = Esc;
buflen = read(0, buf + 1, IOSIZE - 1) + 1;
ESCseen = 0;
}
else
buflen = read(0, buf, IOSIZE);
if (buflen < 0)
{
debug1("Read error: %d - SigHup()ing!\n", errno);
SigHup(SIGARG);
continue;
}
if (buflen == 0)
{
debug("Found EOF - SigHup()ing!\n");
SigHup(SIGARG);
continue;
}
bufp = buf;
if (in_ovl)
{
SetOvlCurr();
(*ovl_process)(&bufp, &buflen);
}
while (buflen > 0)
{
n = ForeNum;
len = inlen[n];
bufp = ProcessInput(bufp, &buflen, inbuf[n], &inlen[n],
sizeof *inbuf);
if (inlen[n] > 0 && len == 0)
inbuf_ct++;
}
if (inbuf_ct > 0)
continue;
}
if (GotSignal && !status)
{
SigHandler();
continue;
}
#ifdef COPY_PASTE
/* Write the copybuffer contents first, if any. jw. */
if (pastelen > 0)
{
n = ForeNum;
debug1("writing pastebuffer (%d)\n", pastelen);
tmp = wtab[n]->ptyfd;
if ( /* FD_ISSET(tmp, &w) && */
(len = write(tmp, pastebuffer,
pastelen > IOSIZE ? IOSIZE : pastelen)) > 0)
{
pastebuffer += len;
pastelen -= len;
debug1("%d bytes pasted\n", len);
if (slowpaste > 0)
{
struct timeval t;
debug1("slowpaste %d\n", slowpaste);
t.tv_usec = (long) (slowpaste * 1000);
t.tv_sec = 0;
select(0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &t);
}
else
continue;
}
/*
* We could not paste? Let's see if the pty did echo the lot.
* Then continue by processing some pty output.
*/
}
#endif
if (GotSignal && !status)
{
SigHandler();
continue;
}
/* Read and process the output from the window descriptors */
for (n = WinList; n != -1; n = p->WinLink)
{
p = wtab[n];
if (in_ovl && ovl_blockfore && n == ForeNum)
continue;
if (p->outlen)
WriteString(p, p->outbuf, p->outlen);
else if (nsel && FD_ISSET(p->ptyfd, &r))
{
nsel--;
if ((len = read(p->ptyfd, buf, IOSIZE)) == -1)
{
#ifdef EWOULDBLOCK
if (errno == EWOULDBLOCK)
len = 0;
#endif
}
#if defined(TIOCPKT) && !defined(sgi)
if (buf[0])
{
debug1("PAKET %x\n", buf[0]);
if (buf[0] & TIOCPKT_NOSTOP)
{
NewAutoFlow(p, 0);
}
if (buf[0] & TIOCPKT_DOSTOP)
{
NewAutoFlow(p, 1);
}
}
if (len > 1)
WriteString(p, buf + 1, len - 1);
#else /* TIOCPKT && !sgi */
if (len > 0)
WriteString(p, buf, len);
#endif /* TIOCPKT && !sgi */
}
if (p->bell == BELL_ON)
{
p->bell = BELL_DONE;
Msg(0, MakeWinMsg(BellString, n));
if (p->monitor == MON_FOUND)
p->monitor = MON_DONE;
}
else if (p->bell == BELL_VISUAL)
{
if (!BellDisplayed)
{
p->bell = BELL_DONE;
Msg(0, VisualBellString);
BellDisplayed = 1;
}
}
else if (p->monitor == MON_FOUND)
{
p->monitor = MON_DONE;
Msg(0, MakeWinMsg(ActivityString, n));
}
}
if (GotSignal && !status)
SigHandler();
#ifdef DEBUG
if (nsel)
debug1("Left over nsel: %d\n", nsel);
#endif
}
/* NOTREACHED */
}
static void SigHandler()
{
struct stat st;
while (GotSignal)
{
GotSignal = 0;
DoWait();
#ifdef SYSV
signal(SIGCLD, SigChld);
#endif
}
if (stat(SockPath, &st) == -1)
{
debug1("SigHandler: Yuck! cannot stat '%s'\n", SockPath);
if (!RecoverSocket())
{
debug("SCREEN cannot recover from corrupt Socket, bye\n");
Finit(1);
}
else
debug1("'%s' reconstructed\n", SockPath);
}
else
debug2("SigHandler: stat '%s' o.k. (%03o)\n", SockPath, st.st_mode);
}
#ifdef DEBUG
int FEpanic;
sig_t FEChld(SIGDEFARG)
{
FEpanic=1;
#ifndef SIGVOID
return((sig_t) 0);
#endif
}
#endif
static sig_t SigChld(SIGDEFARG)
{
debug("SigChld()\n");
GotSignal = 1;
#ifndef SIGVOID
return((sig_t) 0);
#endif
}
sig_t SigHup(SIGDEFARG)
{
debug("SigHup()\n");
if (auto_detach)
Detach(D_DETACH);
else
Finit(0);
#ifndef SIGVOID
return((sig_t) 0);
#endif
}
/*
* the frontend's Interrupt handler
* we forward SIGINT to the backend
*/
static sig_t
AttacherSigInt(SIGDEFARG)
{
Kill(MasterPid, SIGINT);
signal(SIGINT, AttacherSigInt);
# ifndef SIGVOID
return (sig_t) 0;
# endif
}
/*
* the backend's Interrupt handler
* we cannot insert the intrc directly, as we never know
* if fore and ForeNum are valid.
*/
static sig_t SigInt(SIGDEFARG)
{
#if HAZARDOUS
char buf[1];
debug("SigInt()\n");
*buf = (char) intrc;
inlen[ForeNum] = 0;
if (fore && !in_ovl)
write(fore->ptyfd, buf, 1);
#else
debug("SigInt() careful\n");
InterruptPlease = 1;
signal(SIGINT, SigInt);
#endif
#ifndef SIGVOID
return((sig_t) 0);
#endif
}
static sig_t CoreDump(sig)
int sig;
{
setgid(getgid());
setuid(getuid());
unlink("core");
fprintf(stderr, "\r\n[screen caught signal %d.%s]\r\n", sig,
#ifdef SHADOWPW
""
#else /* SHADOWPW */
" (core dumped)"
#endif /* SHADOWPW */
);
fflush(stderr);
Kill(AttacherPid, SIG_BYE);
#ifdef SHADOWPW
eexit(sig);
#else /* SHADOWPW */
abort();
#endif /* SHADOWPW */
#ifndef SIGVOID
return((sig_t) 0);
#endif
}
static void DoWait()
{
register int n, next, pid;
#ifdef BSDWAIT
union wait wstat;
#else
int wstat;
#endif
#ifdef BSDJOBS
# ifndef BSDWAIT
while ((pid = waitpid(-1, &wstat, WNOHANG | WUNTRACED)) > 0)
# else
while ((pid = wait3(&wstat, WNOHANG | WUNTRACED, (struct rusage *) 0)) > 0)
# endif
#else /* BSDJOBS */
while ((pid = wait(&wstat)) < 0)
if (errno != EINTR)
break;
if (pid >= 0)
#endif /* BSDJOBS */
{
for (n = WinList; n != -1; n = next)
{
next = wtab[n]->WinLink;
if (pid == wtab[n]->wpid)
{
#ifdef BSDJOBS
if (WIFSTOPPED(wstat))
{
# ifdef NETHACK
if (nethackflag)
Msg(0, "You regain consciousness.");
else
# endif /* NETHACK */
Msg(0, "Child has been stopped, restarting.");
debug1("WIFSTOPPED: %d SIGCONT\n", wtab[n]->wpid);
if (killpg(wtab[n]->wpid, SIGCONT))
kill(wtab[n]->wpid, SIGCONT);
}
else
#endif
KillWindow(n);
}
}
}
}
void KillWindow(n)
int n;
{
register int i;
/*
* Remove window from linked list.
*/
if (n == WinList) /* WinList = ForeNum */
{
RemoveStatus();
WinList = fore->WinLink;
fore = 0;
}
else
{
i = WinList;
while (wtab[i]->WinLink != n)
i = wtab[i]->WinLink;
wtab[i]->WinLink = wtab[n]->WinLink;
}
FreeWindow(wtab[n]);
wtab[n] = 0;
if (inlen[n] > 0)
{
inlen[n] = 0;
inbuf_ct--;
}
/*
* If the foreground window disappeared check the head of the linked list
* of windows for the most recently used window. If no window is alive at
* all, exit.
*/
if (WinList == -1)
Finit(0);
if (!fore)
SwitchWindow(WinList);
}
static sig_t Finit(i)
int i;
{
register int n, next;
#ifdef SYSV
signal(SIGCLD, SIG_IGN);
#else
signal(SIGCHLD, SIG_IGN);
#endif
signal(SIGHUP, SIG_IGN);
debug1("Finit(%d);\n", i);
for (n = WinList; n != -1; n = next)
{
next = wtab[n]->WinLink;
FreeWindow(wtab[n]);
}
FinitTerm();
SetTTY(0, &OldMode);
#ifdef UTMPOK
RestoreLoginSlot();
#endif
printf("\n[screen is terminating]\n");
freetty();
if (ServerSocket != -1)
{
debug1("we unlink(%s)\n", SockPath);
(void) unlink(SockPath);
}
Kill(AttacherPid, SIG_BYE);
exit(i);
#ifndef SIGVOID
return((sig_t) 0);
#endif
}
void
eexit(e)
int e;
{
if (ServerSocket != -1)
{
debug1("we unlink(%s)\n", SockPath);
(void) unlink(SockPath);
}
exit(e);
}
static void InitKeytab()
{
register unsigned int i;
for (i = 0; i < sizeof(ktab)/sizeof(*ktab); i++)
ktab[i].type = KEY_IGNORE;
ktab['h'].type = ktab[Ctrl('h')].type = KEY_HARDCOPY;
#ifdef BSDJOBS
ktab['z'].type = ktab[Ctrl('z')].type = KEY_SUSPEND;
#endif
ktab['c'].type = ktab[Ctrl('c')].type = KEY_SHELL;
ktab[' '].type = ktab[Ctrl(' ')].type =
ktab['n'].type = ktab[Ctrl('n')].type = KEY_NEXT;
ktab['-'].type = ktab['p'].type = ktab[Ctrl('p')].type = KEY_PREV;
ktab['k'].type = ktab[Ctrl('k')].type = KEY_KILL;
ktab['l'].type = ktab[Ctrl('l')].type = KEY_REDISPLAY;
ktab['w'].type = ktab[Ctrl('w')].type = KEY_WINDOWS;
ktab['v'].type = ktab[Ctrl('v')].type = KEY_VERSION;
ktab['q'].type = ktab[Ctrl('q')].type = KEY_XON;
ktab['s'].type = ktab[Ctrl('s')].type = KEY_XOFF;
ktab['t'].type = ktab[Ctrl('t')].type = KEY_TIME;
ktab['i'].type = ktab[Ctrl('i')].type = KEY_INFO;
ktab['m'].type = ktab[Ctrl('m')].type = KEY_LASTMSG;
ktab['A'].type = KEY_AKA, ktab['A'].args = NULL;
ktab['L'].type = KEY_LOGIN;
ktab[','].type = KEY_LICENSE;
ktab['W'].type = KEY_WIDTH;
ktab['.'].type = KEY_TERMCAP;
ktab[Ctrl('\\')].type = KEY_QUIT;
ktab['d'].type = ktab[Ctrl('d')].type = KEY_DETACH;
ktab['r'].type = ktab[Ctrl('r')].type = KEY_WRAP;
ktab['f'].type = ktab[Ctrl('f')].type = KEY_FLOW;
ktab['C'].type = KEY_CLEAR;
ktab['Z'].type = KEY_RESET;
ktab['H'].type = KEY_LOGTOGGLE;
if (Esc != MetaEsc)
ktab[Esc].type = KEY_OTHER;
else
ktab[Esc].type = KEY_IGNORE;
ktab['M'].type = KEY_MONITOR;
ktab['?'].type = KEY_HELP;
for (i = 0; i <= 9; i++)
ktab['0' + i].type = (enum keytype) (i + (int)KEY_0);
ktab[Ctrl('G')].type = KEY_VBELL;
ktab[':'].type = KEY_COLON;
#ifdef COPY_PASTE
ktab['['].type = ktab[Ctrl('[')].type = KEY_COPY;
ktab[']'].type = ktab[Ctrl(']')].type = KEY_PASTE;
ktab['{'].type = KEY_HISTORY;
ktab['}'].type = KEY_HISTNEXT;
ktab['>'].type = KEY_WRITE_BUFFER;
ktab['<'].type = KEY_READ_BUFFER;
ktab['='].type = KEY_REMOVE_BUFFERS;
#endif
#ifdef POW_DETACH
ktab['D'].type = KEY_POW_DETACH;
#endif
#ifdef LOCK
ktab['x'].type = ktab[Ctrl('x')].type = KEY_LOCK;
#endif
}
/*
* this is a braindamaged hack: if (obuf == NULL) then we provided
* a key_type as a second char in ibuf. not a key.
*/
char *ProcessInput(ibuf, pilen, obuf, polen, obuf_size)
char *ibuf, *obuf;
register int *pilen, *polen, obuf_size;
{
register int n;
register enum keytype k;
register char *s, *p;
char buf[2];
int newwidth;
if (!obuf)
obuf_size = 0;
for (s = ibuf, p = obuf + *polen; *pilen > 0; --*pilen, s++)
{
if (*s == Esc)
{
debug2("'%c %c ", s[0], s[1]);
debug2("%c %c' ", s[2], s[3]);
if (*pilen > 1)
{
--*pilen;
s++;
#if defined(GOULD_NP1)
k = (obuf)?(ktab[*s].type):(enum keytype)(int)(*s);
#else
k = (obuf)?(ktab[*s].type):(enum keytype)(*s);
#endif
debug2("Processinput C-A %02x '%c' ", k, k);
debug1("%s\n", (obuf)?"std":"NOOBUF");
if (*s == MetaEsc)
{
if (*polen < obuf_size)
{
*p++ = Esc;
++*polen;
}
}
else if ((int)k >= (int)KEY_0 && (int)k <= (int)KEY_9)
SwitchWindow((int)k - (int)KEY_0);
else
switch (k)
{
case KEY_TERMCAP:
WriteFile(DUMP_TERMCAP);
break;
case KEY_HARDCOPY:
WriteFile(DUMP_HARDCOPY);
break;
case KEY_LOGTOGGLE:
LogToggle();
break;
#ifdef BSDJOBS
case KEY_SUSPEND:
*pilen = 0;
Detach(D_STOP);
break;
#endif
case KEY_SHELL:
debug("calling MakeWindow with shell\n");
MakeWindow(shellaka, ShellArgs, allflag, default_flow,
0, (char *) 0, loginflag, -1, (char *)0);
break;
case KEY_NEXT:
if (MoreWindows())
SwitchWindow(NextWindow());
break;
case KEY_PREV:
if (MoreWindows())
SwitchWindow(PreviousWindow());
break;
case KEY_KILL:
KillWindow(n = ForeNum);
#ifdef NETHACK
if (nethackflag)
Msg(0, "You destroy poor window %d", n);
#endif
break;
case KEY_QUIT:
Finit(0);
/* NOTREACHED */
case KEY_DETACH:
*pilen = 0;
Detach(D_DETACH);
break;
#ifdef POW_DETACH
case KEY_POW_DETACH:
*pilen = 0;
if (obuf)
{
buf[0] = *s;
buf[1] = '\0';
Msg(0, buf);
read(0, buf, 1);
if (*buf != *s)
{
write(1, "\007", 1);
RemoveStatus();
#ifdef NETHACK
if (nethackflag)
Msg(0, "The blast of disintegration whizzes by you!");
#endif
break;
}
}
Detach(D_POWER); /* detach and kill Attacher's
* parent */
break;
#endif
case KEY_REDISPLAY:
Activate(0);
break;
case KEY_WINDOWS:
ShowWindows();
break;
case KEY_VERSION:
Msg(0, "screen %d.%.2d.%.2d%s (%s) %s", REV, VERS,
PATCHLEVEL, STATE, ORIGIN, DATE);
break;
case KEY_TIME:
ShowTime();
break;
case KEY_INFO:
ShowInfo();
break;
case KEY_OTHER:
if (MoreWindows())
SwitchWindow(fore->WinLink);
break;
case KEY_XON:
if (*polen < obuf_size)
{
*p++ = Ctrl('q');
++*polen;
}
break;
case KEY_XOFF:
if (*polen < obuf_size)
{
*p++ = Ctrl('s');
++*polen;
}
break;
#ifdef LOCK
case KEY_LOCK:
Detach(D_LOCK); /* do it micha's way */
break;
#endif
case KEY_WIDTH:
if (Z0 || WS)
{
if (fore->width == Z0width)
newwidth = Z1width;
else if (fore->width == Z1width)
newwidth = Z0width;
else if (fore->width > (Z0width+Z1width)/2)
newwidth = Z0width;
else
newwidth = Z1width;
ChangeWindowSize(fore, newwidth, fore->height);
Activate(fore->norefresh);
}
else
Msg(0, "Your termcap does not specify how to change the terminal's width.");
break;
case KEY_LOGIN:
SlotToggle(0);
break;
case KEY_AKA:
if (!ktab[*s].args)
InputAKA();
else
strncpy(fore->cmd + fore->akapos, ktab[*s].args[0], 20);
break;
case KEY_COLON:
InputColon();
break;
case KEY_LASTMSG:
Msg(0, "%s", LastMsg);
break;
case KEY_SET:
DoSet(ktab[*s].args);
break;
case KEY_SCREEN:
debug3("KEY_SCREEN DoSc(, ktab[%d].args(='%s','%s')...)\n",
*s, ktab[*s].args[0], ktab[*s].args[1]);
DoScreen("key", ktab[*s].args);
break;
case KEY_CREATE:
debug2("KEY_CREATE MaWi(0, ktab[%d].args(='%s')...)\n",
*s, ktab[*s].args);
MakeWindow((char *) 0, ktab[*s].args, allflag, default_flow, 0, (char *) 0, loginflag, -1, (char *)0);
break;
case KEY_WRAP:
fore->wrap = !fore->wrap;
Msg(0, "%cwrap", fore->wrap ? '+' : '-');
break;
case KEY_FLOW:
if (fore->flow & FLOW_AUTOFLAG)
fore->flow = (fore->flow & FLOW_AUTO) | FLOW_NOW;
else if (fore->flow & FLOW_NOW)
fore->flow &= ~FLOW_NOW;
else
fore->flow = fore->flow ? FLOW_AUTOFLAG|FLOW_AUTO|FLOW_NOW : FLOW_AUTOFLAG;
SetFlow(fore->flow & FLOW_NOW);
Msg(0, "%cflow%s", (fore->flow & FLOW_NOW) ? '+' : '-',
(fore->flow & FLOW_AUTOFLAG) ? "(auto)" : "");
break;
case KEY_CLEAR:
if (fore->state == LIT)
WriteString(fore, "\033[H\033[J", 6);
break;
case KEY_RESET:
if (fore->state == LIT)
WriteString(fore, "\033c", 2);
break;
case KEY_MONITOR:
if (fore->monitor == MON_OFF)
{
fore->monitor = MON_ON;
Msg(0,
"Window %d is now being monitored for all activity.",
ForeNum);
}
else
{
fore->monitor = MON_OFF;
Msg(0,
"Window %d is no longer being monitored for activity.",
ForeNum);
}
break;
case KEY_HELP:
display_help();
break;
case KEY_LICENSE:
display_copyright();
break;
#ifdef COPY_PASTE
case KEY_COPY:
(void) MarkRoutine(PLAIN);
break;
case KEY_HISTNEXT:
if (MarkRoutine(CRAZY))
if (copybuffer != NULL)
{
pastelen = copylen;
pastebuffer = copybuffer;
debug("histnext\n");
}
break;
case KEY_HISTORY:
if (MarkRoutine(TRICKY))
if (copybuffer != NULL)
{
pastelen = copylen;
pastebuffer = copybuffer;
debug1("history new copylen: %d\n", pastelen);
}
break;
case KEY_PASTE:
if (copybuffer == NULL)
{
#ifdef NETHACK
if (nethackflag)
Msg(0, "Nothing happens.");
else
#endif
Msg(0, "empty buffer");
copylen = 0;
break;
}
pastelen = copylen;
pastebuffer = copybuffer;
break;
case KEY_WRITE_BUFFER:
if (copybuffer == NULL)
{
#ifdef NETHACK
if (nethackflag)
Msg(0, "Nothing happens.");
else
#endif
Msg(0, "empty buffer");
copylen = 0;
break;
}
WriteFile(DUMP_EXCHANGE);
break;
case KEY_READ_BUFFER:
ReadFile();
break;
case KEY_REMOVE_BUFFERS:
KillBuffers();
break;
#endif /* COPY_PASTE */
case KEY_VBELL:
if (visual_bell)
{
visual_bell = 0;
Msg(0, "switched to audible bell");
}
else
{
visual_bell = 1;
Msg(0, "switched to visual bell");
}
break;
default:
break;
}
}
else
ESCseen = 1;
--*pilen;
s++;
break;
}
else if (*polen < obuf_size)
{
*p++ = *s;
++*polen;
}
}
return (s);
}
/* Send a terminal report as if it were typed. */
void
Report(wp, fmt, n1, n2)
struct win *wp;
char *fmt;
int n1, n2;
{
register int n, len;
char rbuf[40];
sprintf(rbuf, fmt, n1, n2);
len = strlen(rbuf);
for (n = 0; n < MAXWIN; n++)
{
if (wp == wtab[n])
{
if ((unsigned)(inlen[n] + len) <= sizeof *inbuf)
{
bcopy(rbuf, inbuf[n] + inlen[n], len);
if (inlen[n] == 0)
inbuf_ct++;
inlen[n] += len;
}
break;
}
}/* for */
}
void
SwitchWindow(n)
int n;
{
debug1("SwitchWindow %d\n", n);
if (!wtab[n])
{
ShowWindows();
return;
}
if (wtab[n] == fore)
{
Msg(0, "This IS window %d.", n);
return;
}
SetForeWindow(n);
if (!Detached && !in_ovl)
Activate(fore->norefresh);
}
static void SetForeWindow(n)
int n;
{
/*
* If we come from another window, make it inactive.
*/
if (fore)
fore->active = 0;
ForeNum = n;
fore = wtab[n];
if (!Detached && !in_ovl)
fore->active = 1;
/*
* Place the window at the head of the most-recently-used list.
*/
if ((n = WinList) != ForeNum)
{
/*
* we had a bug here. we sometimes ran into n = -1; and crashed.
* (this is not the perfect fix. "if (...) break;" inserted. jw.)
*/
while (wtab[n]->WinLink != ForeNum)
{
if (wtab[n]->WinLink == -1)
break;
n = wtab[n]->WinLink;
}
wtab[n]->WinLink = fore->WinLink;
fore->WinLink = WinList;
WinList = ForeNum;
}
}
static int NextWindow()
{
register struct win **pp;
for (pp = wtab + ForeNum + 1; pp != wtab + ForeNum; ++pp)
{
if (pp == wtab + MAXWIN)
pp = wtab;
if (*pp)
break;
}
return pp - wtab;
}
static int PreviousWindow()
{
register struct win **pp;
for (pp = wtab + ForeNum - 1; pp != wtab + ForeNum; --pp)
{
if (pp < wtab)
pp = wtab + MAXWIN - 1;
if (*pp)
break;
}
return pp - wtab;
}
static int MoreWindows()
{
if (fore->WinLink != -1)
return 1;
#ifdef NETHACK
if (nethackflag)
Msg(0, "You cannot escape from window %d!", ForeNum);
else
#endif
Msg(0, "No other window.");
return 0;
}
static void FreeWindow(wp)
struct win *wp;
{
#ifdef UTMPOK
RemoveUtmp(wp);
#endif
#ifdef SUIDROOT
(void) chmod(wp->tty, 0666);
(void) chown(wp->tty, 0, 0);
#endif
close(wp->ptyfd);
if (wp->logfp != NULL)
fclose(wp->logfp);
ChangeWindowSize(wp, 0, 0);
Free(wp);
}
int
MakeWindow(prog, args, aflag, flowflag, StartAt, dir, lflag, histheight, term)
char *prog, **args, *dir;
int aflag, flowflag, StartAt, lflag, histheight;
char *term; /* if term is nonzero we assume it "vt100" or the like.. */
{
register struct win **pp, *p;
register int n, f;
int tf, tlflag;
char ebuf[10];
#ifndef TIOCSWINSZ
char libuf[20], cobuf[20];
#endif
char tebuf[25];
pp = wtab + StartAt;
do
{
if (*pp == 0)
break;
if (++pp == wtab + MAXWIN)
pp = wtab;
} while (pp != wtab + StartAt);
if (*pp)
{
Msg(0, "No more windows.");
return -1;
}
if (((tlflag = lflag) == -1) && ((tlflag = loginflag) == -1))
tlflag = LOGINDEFAULT;
#ifdef USRLIMIT
/*
* Count current number of users, if logging windows in.
*/
if (tlflag == 1 && CountUsers() >= USRLIMIT)
{
Msg(0, "User limit reached. Window will not be logged in.");
tlflag = 0;
}
#endif
n = pp - wtab;
debug1("Makewin creating %d\n", n);
if ((f = OpenPTY()) == -1)
{
Msg(0, "No more PTYs.");
return -1;
}
#ifdef SYSV
(void) fcntl(f, F_SETFL, O_NDELAY);
#else
(void) fcntl(f, F_SETFL, FNDELAY);
#endif
#ifdef TIOCPKT
{
# ifdef sgi
/*
* on IRIX 3.3, regardless of stream head's read mode (RNORM/RMSGN/RMSGD)
* we loose data in TIOCPKT mode if our buffer is too small (IOSIZE)
* to hold the whole packet at first read().
* (Marc Boucher)
*/
int flag = 0;
# else /* sgi */
int flag = 1;
# endif /* sgi */
if (ioctl(f, TIOCPKT, &flag))
{
Msg(errno, "TIOCPKT ioctl");
close(f);
return -1;
}
}
#endif
if ((p = (struct win *) malloc(sizeof(struct win))) == 0)
{
close(f);
Msg_nomem;
return -1;
}
bzero((char *) p, (int) sizeof(struct win));
p->ptyfd = f;
p->aflag = aflag;
if (flowflag < 0)
flowflag = default_flow;
p->flow = flowflag | ((flowflag & FLOW_AUTOFLAG) ? (FLOW_AUTO|FLOW_NOW) : FLOW_AUTO);
if (!prog)
prog = Filename(args[0]);
strncpy(p->cmd, prog, MAXSTR - 1);
if ((prog = rindex(p->cmd, '|')) != NULL)
{
*prog++ = '\0';
prog += strlen(prog);
p->akapos = prog - p->cmd;
p->autoaka = 0;
}
else
p->akapos = 0;
p->monitor = default_monitor;
p->norefresh = 0;
strncpy(p->tty, TtyName, MAXSTR - 1);
#ifdef SUIDROOT
(void) chown(TtyName, real_uid, real_gid);
# ifdef UTMPOK
(void) chmod(TtyName, tlflag ? TtyMode : (TtyMode & ~022));
# else
(void) chmod(TtyName, TtyMode);
# endif
#endif
if (histheight < 0)
histheight = default_histheight;
if (ChangeWindowSize(p, default_width, default_height))
{
FreeWindow(p);
return -1;
}
ChangeScrollback(p, histheight, default_width);
ResetScreen(p);
debug("forking...\n");
switch (p->wpid = fork())
{
case -1:
Msg(errno, "fork");
FreeWindow(p);
return -1;
case 0:
signal(SIGHUP, SIG_DFL);
signal(SIGINT, SIG_DFL);
signal(SIGQUIT, SIG_DFL);
signal(SIGTERM, SIG_DFL);
#ifdef BSDJOBS
signal(SIGTTIN, SIG_DFL);
signal(SIGTTOU, SIG_DFL);
#endif
setuid(real_uid);
setgid(real_gid);
if (dir && chdir(dir) == -1)
{
SendErrorMsg("Cannot chdir to %s: %s", dir, sys_errlist[errno]);
eexit(1);
}
freetty();
if ((tf = open(TtyName, O_RDWR)) == -1)
{
SendErrorMsg("Cannot open %s: %s", TtyName, sys_errlist[errno]);
eexit(1);
}
#ifdef SVR4
if (ioctl(tf, I_PUSH, "ptem"))
{
SendErrorMsg("Cannot I_PUSH ptem %s %s", TtyName, sys_errlist[errno]);
eexit(1);
}
if (ioctl(tf, I_PUSH, "ldterm"))
{
SendErrorMsg("Cannot I_PUSH ldterm %s %s", TtyName, sys_errlist[errno]);
eexit(1);
}
if (ioctl(tf, I_PUSH, "ttcompat"))
{
SendErrorMsg("Cannot I_PUSH ttcompat %s %s", TtyName, sys_errlist[errno]);
eexit(1);
}
#endif
(void) dup2(tf, 0);
(void) dup2(tf, 1);
(void) dup2(tf, 2);
#ifdef DEBUG
dfp = stderr;
#endif
closeallfiles();
fgtty();
#ifdef TIOCSWINSZ
glwz.ws_col = p->width;
glwz.ws_row = p->height;
(void) ioctl(0, TIOCSWINSZ, &glwz);
#else
sprintf(libuf, "LINES=%d", p->height);
sprintf(cobuf, "COLUMNS=%d", p->width);
NewEnv[4] = libuf;
NewEnv[5] = cobuf;
#endif
SetTTY(0, &OldMode);
if (aflag)
NewEnv[2] = MakeTermcap(1);
else
NewEnv[2] = Termcap;
if (term && *term && strcmp(screenterm, term) &&
(strlen(term) < 20))
{
char *s1, *s2, tl;
sprintf(tebuf, "TERM=%s", term);
debug2("Makewindow %d with %s\n", n, tebuf);
tl = strlen(term);
NewEnv[1] = tebuf;
if (s1 = index(Termcap, '|'))
{
if (s2 = index(++s1, '|'))
{
if (strlen(Termcap) - (s2 - s1) + tl < 1024)
{
bcopy(s2, s1 + tl, strlen(s2) + 1);
bcopy(term, s1, tl);
}
}
}
}
sprintf(ebuf, "WINDOW=%d", n);
NewEnv[3] = ebuf;
execvpe(*args, args, NewEnv);
SendErrorMsg("Cannot exec %s: %s", *args, sys_errlist[errno]);
exit(1);
} /* end fork switch */
/*
* Place the newly created window at the head of the most-recently-used list.
*/
*pp = p;
p->WinLink = WinList;
WinList = n;
HasWindow = 1;
#ifdef UTMPOK
debug1("MakeWindow will %slog in.\n", tlflag?"":"not ");
if (tlflag == 1)
SetUtmp(p, n);
else
p->slot = (slot_t) -1;
#endif
SetForeWindow(n);
Activate(0);
return n;
}
static void execvpe(prog, args, env)
char *prog, **args, **env;
{
register char *path, *p;
char buf[1024];
char *shargs[MAXARGS + 1];
register int i, eaccess = 0;
if (prog[0] == '/')
path = "";
else if ((path = getenv("PATH")) == 0)
path = DefaultPath;
do
{
p = buf;
while (*path && *path != ':')
*p++ = *path++;
if (p > buf)
*p++ = '/';
strcpy(p, prog);
if (*path)
++path;
execve(buf, args, env);
switch (errno)
{
case ENOEXEC:
shargs[0] = DefaultShell;
shargs[1] = buf;
for (i = 1; (shargs[i + 1] = args[i]) != NULL; ++i)
;
execve(DefaultShell, shargs, env);
return;
case EACCES:
eaccess = 1;
break;
case ENOMEM:
case E2BIG:
case ETXTBSY:
return;
}
} while (*path);
if (eaccess)
errno = EACCES;
}
static void LogToggle()
{
char buf[1024];
sprintf(buf, "screenlog.%d", ForeNum);
if (fore->logfp != NULL)
{
Msg(0, "Logfile \"%s\" closed.", buf);
fclose(fore->logfp);
fore->logfp = NULL;
return;
}
if ((fore->logfp = secfopen(buf, "a")) == NULL)
{
Msg(errno, "Error opening logfile \"%s\"", buf);
return;
}
Msg(0, "%s logfile \"%s\"", ftell(fore->logfp) ? "Appending to" : "Creating", buf);
}
#ifdef NOREUID
static int UserPID;
static sig_t (*Usersigcld)__P(SIGPROTOARG);
#endif
static int UserSTAT;
int UserContext()
{
#ifdef NOREUID
if (eff_uid == real_uid)
return(1);
# ifdef SYSV
Usersigcld = signal(SIGCLD, SIG_DFL);
# else
Usersigcld = signal(SIGCHLD, SIG_DFL);
# endif
debug("UserContext: forking.\n");
switch (UserPID = fork())
{
case -1:
Msg(errno, "fork");
return -1;
case 0:
signal(SIGHUP, SIG_DFL);
signal(SIGINT, SIG_IGN);
signal(SIGQUIT, SIG_DFL);
signal(SIGTERM, SIG_DFL);
# ifdef BSDJOBS
signal(SIGTTIN, SIG_DFL);
signal(SIGTTOU, SIG_DFL);
# endif
setuid(real_uid);
setgid(real_gid);
return 1;
default:
return 0;
}
#else
setreuid(eff_uid, real_uid);
setregid(eff_gid, real_gid);
return 1;
#endif
}
void
UserReturn(val)
int val;
{
#if defined(NOREUID)
if (eff_uid == real_uid)
UserSTAT = val;
else
exit(val);
#else
setreuid(real_uid, eff_uid);
setregid(real_gid, eff_gid);
UserSTAT = val;
#endif
}
int UserStatus()
{
#ifdef NOREUID
int i;
# ifdef BSDWAIT
union wait wstat;
# else
int wstat;
# endif
if (eff_uid == real_uid)
return UserSTAT;
if (UserPID < 0)
return -1;
while ((errno = 0, i = wait(&wstat)) != UserPID)
if (i < 0 && errno != EINTR)
break;
# ifdef SYSV
(void) signal(SIGCLD, Usersigcld);
# else
(void) signal(SIGCHLD, Usersigcld);
# endif
if (i == -1)
return -1;
return (WEXITSTATUS(wstat));
#else
return UserSTAT;
#endif
}
static void ShowWindows()
{
char buf[1024];
register char *s;
register struct win **pp, *p;
register int i, OtherNum = fore->WinLink;
register char *cmd;
for (i = 0, s = buf, pp = wtab; pp < wtab + MAXWIN; ++i, ++pp)
{
if ((p = *pp) == 0)
continue;
if (p->akapos)
{
if (*(p->cmd + p->akapos) && *(p->cmd + p->akapos - 1) != ':')
cmd = p->cmd + p->akapos;
else
cmd = p->cmd + strlen(p->cmd) + 1;
}
else
cmd = p->cmd;
if (s - buf + 5 + strlen(cmd) > fore->width - 1)
break;
if (s > buf)
{
*s++ = ' ';
*s++ = ' ';
}
*s++ = i + '0';
if (i == ForeNum)
*s++ = '*';
else if (i == OtherNum)
*s++ = '-';
if (p->monitor == MON_DONE)
*s++ = '@';
if (p->bell == BELL_DONE)
*s++ = '!';
#ifdef UTMPOK
if (p->slot != (slot_t) 0 && p->slot != (slot_t) -1)
*s++ = '$';
#endif
if (p->logfp != NULL)
{
strcpy(s, "(L)");
s += 3;
}
*s++ = ' ';
strcpy(s, cmd);
s += strlen(s);
if (i == ForeNum)
{
/*
* this is usually done by Activate(), but when looking
* on your current window, you may get annoyed, as there is still
* that temporal '!' and '@' displayed.
* So we remove that after displaying it once.
*/
p->bell = BELL_OFF;
if (p->monitor != MON_OFF)
p->monitor = MON_ON;
}
}
*s++ = ' ';
*s = '\0';
Msg(0, "%s", buf);
}
static void ShowTime()
{
char buf[512];
struct tm *tp;
time_t now;
(void) time(&now);
tp = localtime(&now);
sprintf(buf, "%2d:%02.2d:%02.2d %s", tp->tm_hour, tp->tm_min, tp->tm_sec,
HostName);
{
static int loads = 0;
double loadav[3];
int n;
if (loads >= 0) /* If it failed, don't try again. */
{
loads = getloadavg(loadav, 3);
for (n = 0; n < loads; n++)
{
char *p = buf + strlen(buf);
sprintf(p, " %2.2f", loadav[n]);
}
}
}
Msg(0, "%s", buf);
}
static void ShowInfo()
{
char buf[512], *p;
register struct win *wp = fore;
register int i;
sprintf(buf, "(%d,%d)/(%d,%d)+%d %c%sflow %cins %corg %cwrap %capp %clog %cmon %cr",
wp->x + 1, wp->y + 1, wp->width, wp->height,
wp->histheight,
(wp->flow & FLOW_NOW) ? '+' : '-',
(wp->flow & FLOW_AUTOFLAG) ? "" : ((wp->flow & FLOW_AUTO) ? "(+)" : "(-)"),
wp->insert ? '+' : '-', wp->origin ? '+' : '-',
wp->wrap ? '+' : '-', wp->keypad ? '+' : '-',
(wp->logfp != NULL) ? '+' : '-',
(wp->monitor != MON_OFF) ? '+' : '-',
wp->norefresh ? '-' : '+');
if (ISO2022)
{
p = buf + strlen(buf);
sprintf(p, " G%1d [", wp->LocalCharset);
for (i = 0; i < 4; i++)
p[i + 5] = wp->charsets[i] ? wp->charsets[i] : 'B';
p[9] = ']';
p[10] = '\0';
}
Msg(0, "%s", buf);
}
#if defined(sequent) || defined(_SEQUENT_) || defined(SVR4)
static int OpenPTY()
{
char *m, *s;
register int f;
# ifdef SVR4
char *ptsname();
sig_t (*sigcld)();
if ((f = open("/dev/ptmx", O_RDWR)) == -1)
return(-1);
/*
* SIGCLD set to SIG_DFL for grantpt() because it fork()s and
* exec()s pt_chmod
*/
sigcld = signal(SIGCLD, SIG_DFL);
if ((m = ptsname(f)) == NULL || unlockpt(f) || grantpt(f))
{
signal(SIGCLD, sigcld);
close(f);
return(-1);
}
signal(SIGCLD, sigcld);
strncpy(TtyName, m, sizeof TtyName);
# else /* SVR4 */
if ((f = getpseudotty(&s, &m)) < 0)
return(-1);
strncpy(PtyName, m, sizeof PtyName);
strncpy(TtyName, s, sizeof TtyName);
# endif /* SVR4 */
# ifdef POSIX
tcflush(f, TCIOFLUSH);
# else
(void) ioctl(f, TIOCFLUSH, (char *) 0);
# endif
# ifdef LOCKPTY
(void) ioctl(f, TIOCEXCL, (char *) 0);
# endif
return (f);
}
#else /* defined(sequent) || defined(_SEQUENT_) || defined(SVR4) */
# ifdef MIPS
static int OpenPTY()
{
register char *p, *l, *d;
register f, tf;
register my_minor;
struct stat buf;
strcpy(PtyName, PtyProto);
for (p = PtyName; *p != 'X'; ++p)
;
for (l = PTY_FIRST_CHARS; *p = *l; ++l)
{
for (d = PTY_SECOND_CHARS; p[1] = *d; ++d)
{
if ((f = open(PtyName, O_RDWR)) != -1)
{
fstat(f, &buf);
my_minor = minor(buf.st_rdev);
sprintf(TtyName, "/dev/ttyq%d", my_minor);
if ((tf = open(TtyName, O_RDWR)) != -1)
{
close(tf);
#ifdef LOCKPTY
(void) ioctl(f, TIOCEXCL, (char *)0);
#endif
return f;
}
close(f);
}
}
}
return -1;
}
# else /* MIPS */
# ifdef sgi
static int OpenPTY()
{
register f;
register my_minor;
struct stat buf;
strcpy(PtyName, "/dev/ptc");
f = open(PtyName, O_RDWR|O_NDELAY);
if (f >= 0)
{
if (fstat(f, &buf) < 0)
{
close(f);
return -1;
}
my_minor = minor(buf.st_rdev);
sprintf(TtyName, "/dev/ttyq%d", my_minor);
}
return f;
}
# else /* sgi */
# ifdef _AIX /* RS6000 */
static int OpenPTY()
{
register int i, f, tf;
strcpy (PtyName, "/dev/ptc");
if ((f = open (PtyName, O_RDWR)) != -1)
{
strcpy (TtyName, ttyname (f));
strcpy (PtyName, TtyName);
PtyName [7] = 'c';
#ifdef LOCKPTY
if (ioctl (f, TIOCEXCL, (char *) 0) == -1)
return -1;
#endif
if ((tf = open (TtyName, O_RDWR)) != -1)
{
close (tf);
return f;
}
close (f);
}
return -1;
}
# else /* _AIX, RS6000 */
static int OpenPTY()
{
register char *p, *q, *l, *d;
register int f, tf;
# if !defined(hpux)
debug("Hello, You are none of: sequent, _SEQUENT_, SVR4, MIPS, sgi, AIX\n");
debug(" This OpenPTY() is for hpux, ... and for you?\n");
# endif
strcpy(PtyName, PtyProto);
strcpy(TtyName, TtyProto);
for (p = PtyName; *p != 'X'; ++p)
;
for (q = TtyName; *q != 'X'; ++q)
;
for (l = PTY_FIRST_CHARS; (*p = *l) != '\0'; ++l)
{
for (d = PTY_SECOND_CHARS; (p[1] = *d) != '\0'; ++d)
{
if ((f = open(PtyName, O_RDWR)) != -1)
{
q[0] = *l;
q[1] = *d;
if ((tf = open(TtyName, O_RDWR)) != -1)
{
/* close tf, thus we also get rid of an unwanted
* controlling terminal!
*/
close(tf);
#ifdef LOCKPTY
(void) ioctl(f, TIOCEXCL, (char *) 0);
#endif
return f;
}
close(f);
}
}
}
return -1;
}
# endif /* _AIX, RS6000 */
# endif /* sgi */
# endif /* MIPS */
#endif
void
SetTTY(fd, mp)
int fd;
struct mode *mp;
{
errno = 0;
#ifdef POSIX
tcsetattr(fd, TCSADRAIN, &mp->tio);
# ifdef hpux
ioctl(fd, TIOCSLTC, &mp->m_ltchars);
# endif
#else
# ifdef TERMIO
ioctl(fd, TCSETA, &mp->tio);
# else
/* ioctl(fd, TIOCSETP, &mp->m_ttyb); */
ioctl(fd, TIOCSETC, &mp->m_tchars);
ioctl(fd, TIOCSLTC, &mp->m_ltchars);
ioctl(fd, TIOCLSET, &mp->m_lmode);
ioctl(fd, TIOCSETD, &mp->m_ldisc);
ioctl(fd, TIOCSETP, &mp->m_ttyb);
# endif
#endif
if (errno)
Msg(0, "SetTTY: ioctl failed");
}
void
GetTTY(fd, mp)
int fd;
struct mode *mp;
{
errno = 0;
#ifdef POSIX
tcgetattr(fd, &mp->tio);
# ifdef hpux
ioctl(fd, TIOCGLTC, &mp->m_ltchars);
# endif
#else
# ifdef TERMIO
ioctl(fd, TCGETA, &mp->tio);
# else
ioctl(fd, TIOCGETP, &mp->m_ttyb);
ioctl(fd, TIOCGETC, &mp->m_tchars);
ioctl(fd, TIOCGLTC, &mp->m_ltchars);
ioctl(fd, TIOCLGET, &mp->m_lmode);
ioctl(fd, TIOCGETD, &mp->m_ldisc);
# endif
#endif
if (errno)
Msg(0, "GetTTY: ioctl failed");
}
void
SetMode(op, np)
struct mode *op, *np;
{
*np = *op;
#if defined(TERMIO) || defined(POSIX)
np->tio.c_iflag &= ~ICRNL;
# ifdef ONLCR
np->tio.c_oflag &= ~ONLCR;
# endif
np->tio.c_lflag &= ~(ICANON | ECHO);
/*
* Unfortunately, the master process never will get SIGINT if the real
* terminal is different from the one on which it was originaly started
* (process group membership has not been restored or the new tty could not
* be made controlling again). In my solution, it is the attacher who
* receives SIGINT (because it is always correctly associated with the real
* tty) and forwards it to the master [kill(MasterPid, SIGINT)].
* Marc Boucher (marc@CAM.ORG)
*/
np->tio.c_lflag |= ISIG;
/*
* careful, careful catche monkey..
* never set VMIN and VTIME to zero, if you want blocking io.
*/
np->tio.c_cc[VMIN] = 1;
np->tio.c_cc[VTIME] = 0;
#ifdef VSTART
startc = op->tio.c_cc[VSTART];
#endif
#ifdef VSTOP
stopc = op->tio.c_cc[VSTOP];
#endif
if (iflag)
intrc = op->tio.c_cc[VINTR];
else
intrc = np->tio.c_cc[VINTR] = 0377;
np->tio.c_cc[VQUIT] = 0377;
if (flow == 0)
{
np->tio.c_cc[VINTR] = 0377;
#ifdef VSTART
np->tio.c_cc[VSTART] = 0377;
#endif
#ifdef VSTOP
np->tio.c_cc[VSTOP] = 0377;
#endif
np->tio.c_iflag &= ~IXON;
}
#ifdef VDISCARD
np->tio.c_cc[VDISCARD] = 0377;
#endif
#ifdef VSUSP
np->tio.c_cc[VSUSP] = 0377;
#endif
# ifdef hpux
np->m_ltchars.t_suspc = 0377;
np->m_ltchars.t_dsuspc = 0377;
np->m_ltchars.t_flushc = 0377;
np->m_ltchars.t_lnextc = 0377;
# else
# ifdef VDSUSP
np->tio.c_cc[VDSUSP] = 0377;
# endif
# endif
#else
startc = op->m_tchars.t_startc;
stopc = op->m_tchars.t_stopc;
if (iflag)
intrc = op->m_tchars.t_intrc;
else
intrc = np->m_tchars.t_intrc = -1;
np->m_ttyb.sg_flags &= ~(CRMOD | ECHO);
np->m_ttyb.sg_flags |= CBREAK;
np->m_tchars.t_quitc = -1;
if (flow == 0)
{
np->m_tchars.t_intrc = -1;
np->m_tchars.t_startc = -1;
np->m_tchars.t_stopc = -1;
}
np->m_ltchars.t_suspc = -1;
np->m_ltchars.t_dsuspc = -1;
np->m_ltchars.t_flushc = -1;
np->m_ltchars.t_lnextc = -1;
#endif /* defined(TERMIO) || defined(POSIX) */
}
void
SetFlow(on)
int on;
{
if (flow == on)
return;
#if defined(TERMIO) || defined(POSIX)
if (on)
{
NewMode.tio.c_cc[VINTR] = intrc;
#ifdef VSTART
NewMode.tio.c_cc[VSTART] = startc;
#endif
#ifdef VSTOP
NewMode.tio.c_cc[VSTOP] = stopc;
#endif
NewMode.tio.c_iflag |= IXON;
}
else
{
NewMode.tio.c_cc[VINTR] = 0377;
#ifdef VSTART
NewMode.tio.c_cc[VSTART] = 0377;
#endif
#ifdef VSTOP
NewMode.tio.c_cc[VSTOP] = 0377;
#endif
NewMode.tio.c_iflag &= ~IXON;
}
# ifdef POSIX
if (tcsetattr(0, TCSADRAIN, &NewMode.tio))
# else
if (ioctl(0, TCSETA, &NewMode.tio) != 0)
# endif
debug1("SetFlow: ioctl errno %d\n", errno);
#else
if (on)
{
NewMode.m_tchars.t_intrc = intrc;
NewMode.m_tchars.t_startc = startc;
NewMode.m_tchars.t_stopc = stopc;
}
else
{
NewMode.m_tchars.t_intrc = -1;
NewMode.m_tchars.t_startc = -1;
NewMode.m_tchars.t_stopc = -1;
}
if (ioctl(0, TIOCSETC, &NewMode.m_tchars) != 0)
debug1("SetFlow: ioctl errno %d\n", errno);
#endif /* defined(TERMIO) || defined(POSIX) */
flow = on;
}
/* we return 1 if we could attach one, or 0 if none */
static int Attach(how)
int how;
{
int lasts;
struct msg m;
struct stat st;
char *s;
if (how == MSG_WINCH)
{
bzero((char *) &m, sizeof(m));
m.type = how;
if ((lasts = MakeClientSocket(0, SockName)) >= 0)
{
write(lasts, &m, sizeof(m));
close(lasts);
}
return 0;
}
if (how == MSG_CONT)
{
if ((lasts = MakeClientSocket(0, SockName)) < 0)
{
printf("Sorry, cannot contact session \"%s\" again\r\n",
SockName);
sleep(2);
how = MSG_ATTACH;
}
}
if (how != MSG_CONT)
{
switch (FindSocket(how, &lasts))
{
case 0:
if (rflag == 2)
return 0;
if (quietflag)
eexit(10);
if (SockName && *SockName)
Msg(0, "There is no screen to be %sed matching %s.",
dflag ? "detach" : "resum", SockName);
else
Msg(0, "There is no screen to be %sed.",
dflag ? "detach" : "resum");
/* NOTREACHED */
case 1:
break;
default:
Msg(0, "Type \"screen [-d] -r [pid.]tty.host\" to resume one of them.");
/* NOTREACHED */
}
/*
* Go in UserContext. Advantage is, you can kill your attacher
* when things go wrong. Any disadvantages? jw.
*/
setuid(real_uid);
setgid(real_gid);
SockName = SockNamePtr;
MasterPid = 0;
while (*SockName)
{
if (*SockName > '9' || *SockName < '0')
break;
MasterPid = 10 * MasterPid + *SockName - '0';
SockName++;
}
SockName = SockNamePtr;
debug1("Attach decided, it is '%s'\n", SockPath);
debug1("Attach found MasterPid == %d\n", MasterPid);
if (stat(SockPath, &st) == -1)
Msg(errno, "stat %s", SockPath);
if ((st.st_mode & 0700) != (dflag ? 0700 : 0600))
Msg(0, "That screen is %sdetached.", dflag ? "already " : "not ");
#ifdef REMOTE_DETACH
if (dflag &&
(how == MSG_ATTACH || how == MSG_DETACH || how == MSG_POW_DETACH))
{
strcpy(m.m.detach.tty, attach_tty);
debug1("attach_tty is %s\n", attach_tty);
m.m.detach.dpid = getpid();
# ifdef POW_DETACH
if (dflag == 2)
m.type = MSG_POW_DETACH;
else
# endif
m.type = MSG_DETACH;
if (write(lasts, (char *) &m, sizeof(m)) != sizeof(m))
Msg(errno, "write");
close(lasts);
if (how != MSG_ATTACH)
return 0; /* we detached it. jw. */
sleep(1); /* we dont want to overrun our poor backend. jw. */
if ((lasts = MakeClientSocket(0, SockName)) == -1)
Msg(0, "Cannot contact screen again. Shit.");
}
#endif
}
m.type = how;
strcpy(m.m.attach.tty, attach_tty);
debug1("attach_tty is %s\n", attach_tty);
s = getenv("TERM");
if (s)
{
if (strlen(s) >= MAXPATH - 5)
Msg(0, "$TERM too long - sorry.");
sprintf(m.m.attach.envterm, "TERM=%s", s);
}
else
*m.m.attach.envterm = '\0';
debug1("attach: sending %d bytes... ", sizeof m);
m.m.attach.apid = getpid();
m.m.attach.adaptflag = adaptflag;
m.m.attach.lines = m.m.attach.columns = 0;
if (s = getenv("LINES"))
m.m.attach.lines = atoi(s);
if (s = getenv("COLUMNS"))
m.m.attach.columns = atoi(s);
#ifdef PASSWORD
if (how == MSG_ATTACH || how == MSG_CONT)
trysend(lasts, &m, m.m.attach.password);
else
#endif
{
if (write(lasts, (char *) &m, sizeof(m)) != sizeof(m))
Msg(errno, "write");
close(lasts);
}
debug1("Attach(%d): sent\n", m.type);
Suspended = 0;
rflag = 0;
return 1;
}
#ifdef PASSWORD
static trysendstat;
static sig_t trysendok(SIGDEFARG)
{
trysendstat = 1;
}
static sig_t trysendfail(SIGDEFARG)
{
trysendstat = -1;
# ifdef SYSV
signal(SIG_PW_FAIL, trysendfail);
# endif /* SYSV */
}
static char screenpw[9];
static void trysend(fd, m, pwto)
int fd;
struct msg *m;
char *pwto;
{
char *npw = NULL;
sig_t (*sighup)();
sig_t (*sigusr1)();
int tries;
sigusr1 = signal(SIG_PW_OK, trysendok);
sighup = signal(SIG_PW_FAIL, trysendfail);
for (tries = 0; ; )
{
strcpy(pwto, screenpw);
trysendstat = 0;
if (write(fd, (char *) m, sizeof(*m)) != sizeof(*m))
Msg(errno, "write");
close(fd);
while (trysendstat == 0)
pause();
if (trysendstat > 0)
{
signal(SIG_PW_OK, sigusr1);
signal(SIG_PW_FAIL, sighup);
return;
}
if (++tries > 1 || (npw = getpass("Screen Password:")) == 0 || *npw == 0)
Msg(0, "Password incorrect");
strncpy(screenpw, npw, 8);
if ((fd = MakeClientSocket(0, SockName)) == -1)
Msg(0, "Cannot contact screen again. Shit.");
}
}
#endif /* PASSWORD */
/*
* Unfortunatelly this is also the SIGHUP handler, so we have to
* check, if the backend is already detached.
*/
static sig_t AttacherFinit(SIGDEFARG)
{
struct stat statb;
struct msg m;
int s;
debug("AttacherFinit();\n");
signal(SIGHUP, SIG_IGN);
/* Check if signal comes from backend */
if (SockName)
{
strcpy(SockNamePtr, SockName);
if (stat(SockPath, &statb) == 0 && (statb.st_mode & 0777) != 0600)
{
debug("Detaching backend!\n");
bzero((char *) &m, sizeof(m));
strcpy(m.m.detach.tty, attach_tty);
debug1("attach_tty is %s\n", attach_tty);
m.m.detach.dpid = getpid();
m.type = MSG_HANGUP;
if ((s = MakeClientSocket(0, SockName)) >= 0)
{
write(s, &m, sizeof(m));
close(s);
}
}
}
exit(0);
#ifndef SIGVOID
return((sig_t) 0);
#endif
}
#ifdef POW_DETACH
static sig_t AttacherFinitBye(SIGDEFARG)
{
int ppid;
debug("AttacherFintBye()\n");
freetty();
setuid(real_uid);
setgid(real_gid);
/* we don't want to disturb init (even if we were root), eh? jw */
if ((ppid = getppid()) > 1)
Kill(ppid, SIGHUP); /* carefully say good bye. jw. */
exit(0);
#ifndef SIGVOID
return((sig_t) 0);
#endif
}
#endif
static SuspendPlease;
static sig_t SigStop(SIGDEFARG)
{
debug("SigStop()\n");
SuspendPlease = 1;
#ifndef SIGVOID
return((sig_t) 0);
#endif
}
#ifdef LOCK
static LockPlease;
static sig_t DoLock(SIGDEFARG)
{
debug("DoLock()\n");
LockPlease = 1;
# ifdef SYSV
signal(SIG_LOCK, DoLock);
# endif
# ifndef SIGVOID
return((sig_t) 0);
# endif
}
#endif
#if defined(SIGWINCH) && defined(TIOCGWINSZ)
static SigWinchPlease;
static sig_t SigAttWinch(SIGDEFARG)
{
debug("SigAttWinch()\n");
SigWinchPlease = 1;
# ifndef SIGVOID
return((sig_t) 0);
# endif
}
#endif
static void Attacher()
{
/*
* permanent in UserContext. Advantage is, you can kill your attacher
* when things go wrong. Any disadvantages? jw.
*/
setuid(real_uid); /* XXX: already done in Attach() */
setgid(real_gid); /* XXX: already done in Attach() */
signal(SIGHUP, AttacherFinit);
signal(SIG_BYE, AttacherFinit);
#ifdef POW_DETACH
signal(SIG_POWER_BYE, AttacherFinitBye);
#endif
#ifdef LOCK
signal(SIG_LOCK, DoLock);
#endif
signal(SIGINT, AttacherSigInt);
#ifdef BSDJOBS
signal(SIG_STOP, SigStop);
#endif
#if defined(SIGWINCH) && defined(TIOCGWINSZ)
signal(SIGWINCH, SigAttWinch);
#endif
#ifdef DEBUG
# ifdef SYSV
signal(SIGCLD, FEChld);
# else
signal(SIGCHLD, FEChld);
# endif
#endif
debug("attacher: going for a nap.\n");
dflag = 0;
while (1)
{
pause();
debug("attacher: huh! a signal!\n");
#ifdef DEBUG
if (FEpanic)
{
printf("\n\rSuddenly the Dungeon collapses!! - You die...\n\r");
SetTTY(0, &OldMode);
eexit(1);
}
#endif
#ifdef BSDJOBS
if (SuspendPlease)
{
SuspendPlease = 0;
signal(SIGTSTP, SIG_DFL);
debug("attacher: killing myself SIGTSTP\n");
kill(getpid(), SIGTSTP);
debug1("attacher: continuing from stop(%d)\n", Suspended);
signal(SIG_STOP, SigStop);
(void) Attach(MSG_CONT);
}
#endif
#ifdef LOCK
if (LockPlease)
{
LockPlease = 0;
LockTerminal();
# ifdef SYSV
signal(SIG_LOCK, DoLock);
# endif
(void) Attach(MSG_CONT);
}
#endif /* LOCK */
#if defined(SIGWINCH) && defined(TIOCGWINSZ)
if (SigWinchPlease)
{
SigWinchPlease = 0;
# ifdef SYSV
signal(SIGWINCH, SigAttWinch);
# endif
(void) Attach(MSG_WINCH);
}
#endif /* SIGWINCH */
}
}
#ifdef LOCK
/* ADDED by Rainer Pruy 10/15/87 */
/* POLISHED by mls. 03/10/91 */
static char LockEnd[] = "Welcome back to screen !!\n";
static void LockTerminal()
{
char *prg;
int sig, pid;
sig_t (*sigs[NSIG])__P(SIGPROTOARG);
for (sig = 1; sig < NSIG; sig++)
{
sigs[sig] = signal(sig, SIG_IGN);
}
SetTTY(0, &OldMode);
printf("\n");
prg = getenv("LOCKPRG");
if (prg && strcmp(prg, "builtin") && !access(prg, X_OK))
{
# ifdef SYSV
signal(SIGCLD, SIG_DFL);
# else /* SYSV */
signal(SIGCHLD, SIG_DFL);
# endif /* SYSV */
debug1("lockterminal: '%s' seems executable, execl it!\n", prg);
if ((pid = fork()) == 0)
{
/* Child */
setuid(real_uid); /* this should be done already */
setgid(real_gid);
closeallfiles(); /* important: /etc/shadow may be open */
execl(prg, "SCREEN-LOCK", NULL);
exit(errno);
}
if (pid == -1)
{
#ifdef NETHACK
if (nethackflag)
Msg(errno, "Cannot fork terminal - lock failed");
else
#endif
Msg(errno, "Cannot lock terminal - fork failed");
}
else
{
#ifdef BSDWAIT
union wait wstat;
#else
int wstat;
#endif
int wret;
#ifdef hpux
signal(SIGCLD, SIG_DFL);
#endif
errno = 0;
while (((wret = wait((int *) &wstat)) != pid) ||
((wret == -1) && (errno == EINTR))
)
errno = 0;
if (errno)
{
perror("Lock");
sleep(2);
}
else if (WTERMSIG(wstat) != 0)
{
fprintf(stderr, "Lock: %s: Killed by signal: %d%s\n", prg,
WTERMSIG(wstat), WIFCORESIG(wstat) ? " (Core dumped)" : "");
sleep(2);
}
else if (WEXITSTATUS(wstat))
{
debug2("Lock: %s: return code %d\n", prg, WEXITSTATUS(wstat));
}
else
printf(LockEnd);
}
}
else
{
if (prg)
{
debug1("lockterminal: '%s' seems NOT executable, we use our builtin\n", prg);
}
else
{
debug("lockterminal: using buitin.\n");
}
screen_builtin_lck();
}
/* reset signals */
for (sig = 1; sig < NSIG; sig++)
{
if (sigs[sig] != (sig_t(*) ()) - 1)
signal(sig, sigs[sig]);
}
} /* LockTerminal */
/* -- original copyright by Luigi Cannelloni 1985 (luigi@faui70.UUCP) -- */
void
screen_builtin_lck()
{
char fullname[100], *cp1, message[BUFSIZ];
char c, *pass, mypass[9];
#ifdef SHADOWPW
struct spwd *sss = NULL;
#endif
int t;
#ifdef undef
/* get password entry */
if ((ppp = getpwuid(real_uid)) == NULL)
{
fprintf(stderr, "screen_builtin_lck: No passwd entry.\007\n");
sleep(2);
return;
}
if (!isatty(0))
{
fprintf(stderr, "screen_builtin_lck: Not a tty.\007\n");
sleep(2);
return;
}
#endif
pass = ppp->pw_passwd;
realpw:
for (t = 0; t < 13; t++)
{
c = pass[t];
if (!(c == '.' || c == '/' ||
(c >= '0' && c <= '9') ||
(c >= 'a' && c <= 'z') ||
(c >= 'A' && c <= 'Z')))
break;
}
if (t < 13)
{
debug("builtin_lock: ppp->pw_passwd bad, has it a shadow?\n");
#ifdef SHADOWPW
setspent(); /* rewind shadow file */
if ((sss == NULL) && (sss = getspnam(ppp->pw_name)))
{
pass = sss->sp_pwdp;
goto realpw;
}
#endif /* SHADOWPW */
if (pass = getpass("Key: "))
{
strncpy(mypass, pass, 8);
mypass[8] = 0;
if (*mypass == 0)
return;
if (pass = getpass("Again: "))
{
if (strcmp(mypass, pass))
{
fprintf(stderr, "Passwords don't match.\007\n");
sleep(2);
return;
}
}
}
if (pass == 0)
{
fprintf(stderr, "Getpass error.\007\n");
sleep(2);
return;
}
pass = 0;
}
debug("screen_builtin_lck looking in gcos field\n");
strcpy(fullname, ppp->pw_gecos);
if ((cp1 = index(fullname, ',')) != NULL)
*cp1 = '\0';
if ((cp1 = index(fullname, '&')) != NULL)
{
sprintf(cp1, "%s", ppp->pw_name);
*cp1 = islower(*cp1) ? toupper(*cp1) : *cp1;
}
sprintf(message, "Screen used by %s <%s>.\nPassword:\007",
fullname, ppp->pw_name);
/* loop here to wait for correct password */
for (;;)
{
debug("screen_builtin_lck awaiting password\n");
if ((cp1 = getpass(message)) == NULL)
{
AttacherFinit(SIGARG);
/* NOTREACHED */
}
if (pass)
{
if (!strcmp(crypt(cp1, pass), pass))
break;
}
else
{
if (!strcmp(cp1, mypass))
break;
}
debug("screen_builtin_lck: NO!!!!!\n");
}
debug("password ok.\n");
}
#endif /* LOCK */
/*
* Detach now has the following modes:
* D_DETACH SIG_BYE detach backend and exit attacher
* D_STOP SIG_STOP stop attacher (and detach backend)
* D_REMOTE SIG_BYE remote detach -- reattach to new attacher
* D_POWER SIG_POWER_BYE power detach -- attacher kills his parent
* D_REMOTE_POWER SIG_POWER_BYE remote power detach -- both
* D_LOCK SIG_LOCK lock the attacher
* (jw)
* we always remove our utmp slots. (even when "lock" or "stop")
* Note: Take extra care here, we may be called by unterrupt!
*/
void
Detach(mode)
int mode;
{
int sign = 0;
#ifdef UTMPOK
register int n;
#endif
if (Detached)
return;
debug1("Detach(%d)\n", mode);
if (fore && status)
RemoveStatus();
signal(SIGHUP, SIG_IGN);
SetTTY(0, &OldMode);
FinitTerm();
switch (mode)
{
case D_DETACH:
printf("\n[detached]\n");
sign = SIG_BYE;
break;
#ifdef BSDJOBS
case D_STOP:
(void) fflush(stdout);
sign = SIG_STOP;
break;
#endif
#ifdef REMOTE_DETACH
case D_REMOTE:
printf("\n[remote detached]\n");
sign = SIG_BYE;
break;
#endif
#ifdef POW_DETACH
case D_POWER:
printf("\n[power detached]\n");
if (PowDetachString)
printf("%s\n", PowDetachString);
sign = SIG_POWER_BYE;
break;
#ifdef REMOTE_DETACH
case D_REMOTE_POWER:
printf("\n[remote power detached]\n");
if (PowDetachString)
printf("%s\n", PowDetachString);
sign = SIG_POWER_BYE;
break;
#endif
#endif
case D_LOCK:
ClearDisplay();
sign = SIG_LOCK;
/* tell attacher to lock terminal with a lockprg. */
break;
}
#ifdef UTMPOK
for (n = WinList; n != -1; n = wtab[n]->WinLink)
if (wtab[n]->slot != (slot_t) -1)
{
RemoveUtmp(wtab[n]);
/*
* Set the slot to 0 to get the window
* logged in again.
*/
wtab[n]->slot = (slot_t) 0;
}
RestoreLoginSlot();
#endif
freetty();
(void) chmod(SockPath, /* S_IFSOCK | */ 0600); /* Flag detached-ness */
/*
* tell father to father what to do. We do that after we
* freed the tty, thus getty feels more comfortable on hpux
* if it was a power detach.
*/
Kill(AttacherPid, sign);
debug2("Detach: Signal %d to Attacher(%d)!\n", sign, AttacherPid);
if (mode != D_LOCK && mode != D_STOP)
AttacherPid = 0;
Detached = 1;
Suspended = (mode == D_STOP) ? 1 : 0;
if (fore)
fore->active = 0;
debug("Detach returns, we are successfully detached.\n");
}
void
Kill(pid, sig)
int pid, sig;
{
if (pid < 2)
return;
(void) kill(pid, sig);
}
static int IsSymbol(e, s)
register char *e, *s;
{
register char *p;
register int n;
for (p = e; *p && *p != '='; ++p)
;
if (*p)
{
*p = '\0';
n = strcmp(e, s);
*p = '=';
return n == 0;
}
return 0;
}
static void MakeNewEnv()
{
register char **op, **np;
static char buf[MAXSTR];
for (op = environ; *op; ++op)
;
NewEnv = np = (char **) malloc((unsigned) (op - environ + 6 + 1) * sizeof(char **));
if (!NewEnv)
Msg_nomem;
if (strlen(SockName) > MAXSTR - 5)
SockName = "?";
sprintf(buf, "STY=%s", SockName);
*np++ = buf; /* NewEnv[0] */
*np++ = Term; /* NewEnv[1] */
#ifdef TIOCSWINSZ
np += 2; /* room for TERMCAP and WINDOW */
#else
np += 4; /* room for TERMCAP WINDOW LINES COLUMNS */
#endif
for (op = environ; *op; ++op)
{
if (!IsSymbol(*op, "TERM") && !IsSymbol(*op, "TERMCAP")
&& !IsSymbol(*op, "STY") && !IsSymbol(*op, "WINDOW")
&& !IsSymbol(*op, "SCREENCAP")
#ifndef TIOCGWINSZ
&& !IsSymbol(*op, "LINES") && !IsSymbol(*op, "COLUMNS")
#endif
)
*np++ = *op;
}
*np = 0;
}
void
#ifdef USEVARARGS
/*VARARGS2*/
# if defined(__STDC__)
Msg(int err, char *fmt, ...)
# else
Msg(err, fmt, va_alist)
int err;
char *fmt;
va_dcl
# endif
{
static va_list ap = 0;
#else
/*VARARGS2*/
Msg(err, fmt, p1, p2, p3, p4, p5, p6)
int err;
char *fmt;
unsigned long p1, p2, p3, p4, p5, p6;
{
#endif
char buf[MAXPATH*2];
char *p = buf;
if (Detached)
return;
#ifdef USEVARARGS
# if defined(__STDC__)
va_start(ap, fmt);
# else
va_start(ap);
# endif
(void) vsprintf(p, fmt, ap);
va_end(ap);
#else
sprintf(p, fmt, p1, p2, p3, p4, p5, p6);
#endif
if (err)
{
p += strlen(p);
if (err > 0 && err < sys_nerr)
sprintf(p, ": %s", sys_errlist[err]);
else
sprintf(p, ": Error %d", err);
}
if (HasWindow)
{
debug1("Msg('%s');\n", p);
MakeStatus(buf);
}
else
{
printf("%s\r\n", buf);
if (DeadlyMsg)
{
debug1("Msg('%s') screen is not up, exiting..\n", buf);
Kill(AttacherPid, SIG_BYE);
eexit(1);
}
else
debug1("Harmless; Msg('%s');\n", buf);
}
DeadlyMsg = 1;
}
char *Filename(s)
char *s;
{
register char *p;
if (s == NULL)
return s;
p = s + strlen(s) - 1;
while (p >= s && *p != '/')
--p;
return ++p;
}
/*
* '^' is allowed as an escape mechanism for control characters. jw.
*/
static char *MakeWinMsg(s, n)
register char *s;
int n;
{
static char buf[MAXSTR];
register char *p = buf;
register int ctrl;
ctrl = 0;
for (; *s && p < buf + MAXSTR - 1; s++, p++)
if (ctrl)
{
ctrl = 0;
if (*s == '^' || *s < 64)
*p = *s;
else
*p = *s - 64;
}
else
{
switch (*s)
{
case '%':
*p = n + '0';
break;
case '~':
*p = BELL;
break;
case '^':
ctrl = 1;
*p-- = '^';
break;
default:
*p = *s;
break;
}
}
*p = '\0';
return buf;
}